diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71594a4c..208f538e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,43 +1,71 @@ name: CI on: push: - branches: - - main + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' pull_request: - branches: - - main - - next + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: + timeout-minutes: 15 name: lint - runs-on: ubuntu-latest - + runs-on: ${{ github.repository == 'stainless-sdks/braintrust-sdk-kotlin' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 - - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v3 - - name: Set up Java uses: actions/setup-java@v4 with: distribution: temurin java-version: | 8 - 17 + 21 cache: gradle - name: Set up Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v4 - name: Run lints run: ./scripts/lint + + build: + timeout-minutes: 15 + name: build + runs-on: ${{ github.repository == 'stainless-sdks/braintrust-sdk-kotlin' && '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: ubuntu-latest - + runs-on: ${{ github.repository == 'stainless-sdks/braintrust-sdk-kotlin' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -47,7 +75,7 @@ jobs: distribution: temurin java-version: | 8 - 17 + 21 cache: gradle - name: Set up Gradle @@ -55,4 +83,3 @@ jobs: - name: Run tests run: ./scripts/test - diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 18cefe04..188f46dd 100755 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -17,23 +17,25 @@ jobs: - uses: actions/checkout@v4 - name: Set up Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: | 8 - 17 + 21 cache: gradle - name: Set up Gradle uses: gradle/gradle-build-action@v2 - name: Publish to Sonatype - run: | - ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" + run: |- + export -- GPG_SIGNING_KEY_ID + printenv -- GPG_SIGNING_KEY | gpg --batch --passphrase-fd 3 --import 3<<< "$GPG_SIGNING_PASSWORD" + GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')" + ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache env: SONATYPE_USERNAME: ${{ secrets.BRAINTRUST_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.BRAINTRUST_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY_ID: ${{ secrets.BRAINTRUST_SONATYPE_GPG_SIGNING_KEY_ID || secrets.GPG_SIGNING_KEY_ID }} GPG_SIGNING_KEY: ${{ secrets.BRAINTRUST_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} GPG_SIGNING_PASSWORD: ${{ secrets.BRAINTRUST_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 3548e11a..cc2dc33e 100755 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -20,6 +20,5 @@ jobs: env: SONATYPE_USERNAME: ${{ secrets.BRAINTRUST_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.BRAINTRUST_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY_ID: ${{ secrets.BRAINTRUST_SONATYPE_GPG_SIGNING_KEY_ID || secrets.GPG_SIGNING_KEY_ID }} GPG_SIGNING_KEY: ${{ secrets.BRAINTRUST_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} GPG_SIGNING_PASSWORD: ${{ secrets.BRAINTRUST_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} diff --git a/.gitignore b/.gitignore index 39c31e3e..b1346e6d 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .prism.log .gradle .idea -build +.kotlin +build/ codegen.log kls_database.db diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6b7b74c5..da59f99e 100755 --- 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/.stats.yml b/.stats.yml index ac9200d3..2e43a77b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,4 @@ -configured_endpoints: 104 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/manugoyal%2Fbraintrust-sdk-9d216c8243fe39ba2ffe3bffaab0dba53f1c04b7216d22f9072f6611233de0c7.yml +configured_endpoints: 110 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/manugoyal%2Fbraintrust-sdk-f0d64ce0e0efde75f9c171f7f3c3d4a72f00a77abb3bc5a7d65b7be1e715689b.yml +openapi_spec_hash: a027e48cc6aea2fab3cbdd38f4081119 +config_hash: dca6e2cafd0764aa5fa3e78987e8b07c diff --git a/CHANGELOG.md b/CHANGELOG.md index 75e668e1..9ed9f587 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,216 @@ # Changelog +## 0.4.0 (2025-12-03) + +Full Changelog: [v0.3.0...v0.4.0](https://github.com/braintrustdata/braintrust-kotlin/compare/v0.3.0...v0.4.0) + +### ⚠ BREAKING CHANGES + +* **client:** extract auto pagination to shared classes +* **client:** **Migration:** - If you were referencing the `AutoPager` class on a specific `*Page` or `*PageAsync` type, then you should instead reference the shared `AutoPager` and `AutoPagerAsync` types, under the `core` package + - If you were referencing `getNextPage` or `getNextPageParams`: + - Swap to `nextPage()` and `nextPageParams()` + - Note that these both now return non-nullable types (use `hasNextPage()` before calling these, since they will throw if it's impossible to get another page) +* **client:** refactor exception structure and methods ([#132](https://github.com/braintrustdata/braintrust-kotlin/issues/132)) +* **client:** **Migration:** Previously you would access error JSON on an exception via `exception.error()._additionalProperties()`, which would return `Map`. Now you would access this via `exception.body()`, which returns `JsonValue`. You should no longer assume that the returned error JSON is an object. You can check via `exception.body().asObject()`. +* **client:** refactor multipart formdata impl ([#99](https://github.com/braintrustdata/braintrust-kotlin/issues/99)) +* **client:** **Migration:** 1. Builder methods that used to take `contentType` and `filename` as positional parameters after the main argument now no longer do. To set a custom `contentType` or `filename`, pass `MultipartField`, which can be constructed via `MultipartField.builder()`. 2. It's unlikely you were referencing it, but `MultipartFormValue` is now called `MultipartField` if you were. + +### Features + +* add retryable exception ([a2c54ff](https://github.com/braintrustdata/braintrust-kotlin/commit/a2c54fff92abe4d534dca53c8e2025d405cccc35)) +* **api:** api update ([#50](https://github.com/braintrustdata/braintrust-kotlin/issues/50)) ([5e52131](https://github.com/braintrustdata/braintrust-kotlin/commit/5e521318ca6b5c34c75e917f1a5e42d086b2278d)) +* **api:** api update ([#52](https://github.com/braintrustdata/braintrust-kotlin/issues/52)) ([c8a8e0e](https://github.com/braintrustdata/braintrust-kotlin/commit/c8a8e0e5196677b4e49038b5db881b1b01c3157d)) +* **api:** api update ([#53](https://github.com/braintrustdata/braintrust-kotlin/issues/53)) ([b3c1bb2](https://github.com/braintrustdata/braintrust-kotlin/commit/b3c1bb2f7b82097792866386b22150e7b3b11b5a)) +* **api:** api update ([#54](https://github.com/braintrustdata/braintrust-kotlin/issues/54)) ([9a85a86](https://github.com/braintrustdata/braintrust-kotlin/commit/9a85a862e084f405f6497c4f733a260af8a83872)) +* **api:** manual updates ([#117](https://github.com/braintrustdata/braintrust-kotlin/issues/117)) ([b68f811](https://github.com/braintrustdata/braintrust-kotlin/commit/b68f81175a329e8a1b0dfc08e769fc32cbf8bd90)) +* **api:** manual updates ([#118](https://github.com/braintrustdata/braintrust-kotlin/issues/118)) ([a820adb](https://github.com/braintrustdata/braintrust-kotlin/commit/a820adbbbe4fb32cfa3925bbdd645ad5b95014a0)) +* **api:** manual updates ([#120](https://github.com/braintrustdata/braintrust-kotlin/issues/120)) ([4ef778b](https://github.com/braintrustdata/braintrust-kotlin/commit/4ef778ba5932835225c60f5f507c0025fa415e6b)) +* **api:** manual updates ([#121](https://github.com/braintrustdata/braintrust-kotlin/issues/121)) ([093acc4](https://github.com/braintrustdata/braintrust-kotlin/commit/093acc4aba4c4b4fea67b606d83f31f68e046743)) +* **api:** manual updates ([#75](https://github.com/braintrustdata/braintrust-kotlin/issues/75)) ([8f7b570](https://github.com/braintrustdata/braintrust-kotlin/commit/8f7b57048a316a8dc5606b84047ed269dda462f3)) +* **api:** manual updates ([#77](https://github.com/braintrustdata/braintrust-kotlin/issues/77)) ([8732e08](https://github.com/braintrustdata/braintrust-kotlin/commit/8732e08757d82f5e82dfd6d61bf8ca0d69e15baa)) +* **api:** manual updates ([#79](https://github.com/braintrustdata/braintrust-kotlin/issues/79)) ([5b6c4e5](https://github.com/braintrustdata/braintrust-kotlin/commit/5b6c4e511b61d00cbf7ffbab6bdbd8848211b43a)) +* **api:** manual updates ([#80](https://github.com/braintrustdata/braintrust-kotlin/issues/80)) ([ecaf2ae](https://github.com/braintrustdata/braintrust-kotlin/commit/ecaf2ae89a33a162f75b86834ca229e025c197a5)) +* **api:** manual updates ([#81](https://github.com/braintrustdata/braintrust-kotlin/issues/81)) ([72e13e2](https://github.com/braintrustdata/braintrust-kotlin/commit/72e13e216b5ec668bd170e0be2b3cecba4598466)) +* **api:** manual updates ([#82](https://github.com/braintrustdata/braintrust-kotlin/issues/82)) ([b54f251](https://github.com/braintrustdata/braintrust-kotlin/commit/b54f251e1ada7538adf7ce67656f7cb2ca603c92)) +* **api:** manual updates ([#83](https://github.com/braintrustdata/braintrust-kotlin/issues/83)) ([456fe14](https://github.com/braintrustdata/braintrust-kotlin/commit/456fe14c2dc726c306907eb4e3a56f94eb632386)) +* **api:** manual updates ([#84](https://github.com/braintrustdata/braintrust-kotlin/issues/84)) ([7849b85](https://github.com/braintrustdata/braintrust-kotlin/commit/7849b858d7c6edec79d6584a53f5be2ccaaf5ace)) +* **api:** manual updates ([#91](https://github.com/braintrustdata/braintrust-kotlin/issues/91)) ([29bee4e](https://github.com/braintrustdata/braintrust-kotlin/commit/29bee4eda1af9bc45d88ff99cffb118fed48b73c)) +* **client:** accept `InputStream` and `Path` for file params ([#102](https://github.com/braintrustdata/braintrust-kotlin/issues/102)) ([d68c4ee](https://github.com/braintrustdata/braintrust-kotlin/commit/d68c4ee117512eb8095c7b2fdbb08973961e452a)) +* **client:** add `{QueryParams,Headers}#put(String, JsonValue)` methods ([430e2f3](https://github.com/braintrustdata/braintrust-kotlin/commit/430e2f32cd9825597a6eb6b33ae34ea47ef7734c)) +* **client:** add a `withOptions` method ([0599455](https://github.com/braintrustdata/braintrust-kotlin/commit/0599455e28b280d36dcd22eefd95233c978d0e92)) +* **client:** add enum validation method ([1e676fb](https://github.com/braintrustdata/braintrust-kotlin/commit/1e676fb297914ce740c8fea2708bc624585dad01)) +* **client:** add https config options ([789d35f](https://github.com/braintrustdata/braintrust-kotlin/commit/789d35f9cd6690919eed1c34e28bb4c2c2ad3fb9)) +* **client:** allow configuring env via system properties ([4604608](https://github.com/braintrustdata/braintrust-kotlin/commit/4604608aecce306f042ae3acaf4fcef450ae8b1e)) +* **client:** allow configuring timeouts granularly ([#97](https://github.com/braintrustdata/braintrust-kotlin/issues/97)) ([e92c8c8](https://github.com/braintrustdata/braintrust-kotlin/commit/e92c8c89970ad42f18b95aea2fb72c04fc19c4b3)) +* **client:** allow providing some params positionally ([c543351](https://github.com/braintrustdata/braintrust-kotlin/commit/c54335174d22ad222d9baf176f252687faf74a6e)) +* **client:** detect binary incompatible jackson versions ([#103](https://github.com/braintrustdata/braintrust-kotlin/issues/103)) ([2576b86](https://github.com/braintrustdata/braintrust-kotlin/commit/2576b865737f56bfaeb12a400a376b97224e6fbe)) +* **client:** ensure compat with proguard ([42635ab](https://github.com/braintrustdata/braintrust-kotlin/commit/42635abb640511be1d954fd40e5a61260cd9ee5a)) +* **client:** expose request body setter and getter ([#145](https://github.com/braintrustdata/braintrust-kotlin/issues/145)) ([9f61f5b](https://github.com/braintrustdata/braintrust-kotlin/commit/9f61f5bd1160c515abfebcf778fda26324fc5fc1)) +* **client:** expose sleeper option ([dfcb76f](https://github.com/braintrustdata/braintrust-kotlin/commit/dfcb76f7827aac295d57767a5669d18b6cf0960b)) +* **client:** extract auto pagination to shared classes ([12a94f0](https://github.com/braintrustdata/braintrust-kotlin/commit/12a94f0b0ec372b21edb91ec7019311669711166)) +* **client:** implement per-endpoint base URL support ([1839ec8](https://github.com/braintrustdata/braintrust-kotlin/commit/1839ec8f1436b336b033c09e1894aa8a39d0a83b)) +* **client:** make datetime deserialization more lenient ([#144](https://github.com/braintrustdata/braintrust-kotlin/issues/144)) ([e1abefb](https://github.com/braintrustdata/braintrust-kotlin/commit/e1abefb1c8a96d9149e57c08d04cfad6ff21a2ff)) +* **client:** make pagination robust to missing data ([71968b4](https://github.com/braintrustdata/braintrust-kotlin/commit/71968b4109ba33d824a9dbdf7567aa90b7b0ff6a)) +* **client:** make union deserialization more robust ([#143](https://github.com/braintrustdata/braintrust-kotlin/issues/143)) ([1e676fb](https://github.com/braintrustdata/braintrust-kotlin/commit/1e676fb297914ce740c8fea2708bc624585dad01)) +* **client:** support a lower jackson version ([#137](https://github.com/braintrustdata/braintrust-kotlin/issues/137)) ([8fe19ac](https://github.com/braintrustdata/braintrust-kotlin/commit/8fe19ac1626f12461819857e5716bd1de3a514be)) +* **client:** support raw response access ([#98](https://github.com/braintrustdata/braintrust-kotlin/issues/98)) ([402d7d4](https://github.com/braintrustdata/braintrust-kotlin/commit/402d7d4ba7447e1b8a2fb878480369526690e837)) +* **client:** support setting base URL via env var ([a051a62](https://github.com/braintrustdata/braintrust-kotlin/commit/a051a62264ecc5c331df0674517249f5c2fa2b78)) +* **client:** throw on incompatible jackson version ([8fe19ac](https://github.com/braintrustdata/braintrust-kotlin/commit/8fe19ac1626f12461819857e5716bd1de3a514be)) +* generate and publish docs ([#104](https://github.com/braintrustdata/braintrust-kotlin/issues/104)) ([af10dfa](https://github.com/braintrustdata/braintrust-kotlin/commit/af10dfabe69cce01485d16534891e0fec0d2c2c9)) + + +### Bug Fixes + +* **ci:** release-doctor — report correct token name ([c4b98ad](https://github.com/braintrustdata/braintrust-kotlin/commit/c4b98adfe154dc1f470fffa70f37cc4d0c590fbe)) +* **ci:** use java-version 21 for publish step ([e72ceec](https://github.com/braintrustdata/braintrust-kotlin/commit/e72ceec842fe5cd4019fdb1ff416e9256fb3f82b)) +* **client:** accidental mutability of some classes ([ff29dfc](https://github.com/braintrustdata/braintrust-kotlin/commit/ff29dfcd127f51dac70aa31f4a3abec0120ded7b)) +* **client:** bump max requests per host to max requests (5 -> 64) ([267ec75](https://github.com/braintrustdata/braintrust-kotlin/commit/267ec753ab9a5efd0c5065de14bdb93168b4dc51)) +* **client:** bump to better jackson version ([1ecc879](https://github.com/braintrustdata/braintrust-kotlin/commit/1ecc879a867b67629251c7ac899082753a1e3758)) +* **client:** deserialization of empty objects ([0ffe055](https://github.com/braintrustdata/braintrust-kotlin/commit/0ffe0554d06ac07d439c61b46ef7e7a065cc4ed5)) +* **client:** don't call `validate()` during deserialization if we don't have to ([#140](https://github.com/braintrustdata/braintrust-kotlin/issues/140)) ([4819d56](https://github.com/braintrustdata/braintrust-kotlin/commit/4819d5650518a5e02a33784af8a9b1e071a16d6e)) +* **client:** don't close client on `withOptions` usage when original is gc'd ([f34eb56](https://github.com/braintrustdata/braintrust-kotlin/commit/f34eb564bdd06ae284e331b5f7dce5c5c303e345)) +* **client:** ensure error handling always occurs ([9c943ae](https://github.com/braintrustdata/braintrust-kotlin/commit/9c943ae891f9e93fb56b292f46009448c9f23134)) +* **client:** ensure single timer is created per client ([dfcb76f](https://github.com/braintrustdata/braintrust-kotlin/commit/dfcb76f7827aac295d57767a5669d18b6cf0960b)) +* **client:** incorrect `getPackageVersion` impl ([c901eb6](https://github.com/braintrustdata/braintrust-kotlin/commit/c901eb680764b5e1e82576e547b52710d5ba08d9)) +* **client:** limit json deserialization coercion ([#141](https://github.com/braintrustdata/braintrust-kotlin/issues/141)) ([346b726](https://github.com/braintrustdata/braintrust-kotlin/commit/346b7260ef162e4afaf2d6a0390c9ac43ef1fe63)) +* **client:** map deserialization bug ([0092e84](https://github.com/braintrustdata/braintrust-kotlin/commit/0092e8412d90c313cf74c739e47e757ea97dca26)) +* **client:** multi-value header serialization ([992e97d](https://github.com/braintrustdata/braintrust-kotlin/commit/992e97d6f7b3b745fad8f72575f45f34f5259879)) +* **client:** r8 support ([3eeb5d5](https://github.com/braintrustdata/braintrust-kotlin/commit/3eeb5d5435cbf40488e6ea7d0a286ee2fffc28f6)) +* **client:** support kotlin 1.8 runtime ([#129](https://github.com/braintrustdata/braintrust-kotlin/issues/129)) ([0437e08](https://github.com/braintrustdata/braintrust-kotlin/commit/0437e080354ad8a48d860f06863448be15097d3c)) +* fix casing issue ([a2c6996](https://github.com/braintrustdata/braintrust-kotlin/commit/a2c6996b9017a38d552431894ab9fbb6fbc30e28)) +* pluralize `list` response variables ([#142](https://github.com/braintrustdata/braintrust-kotlin/issues/142)) ([a82733e](https://github.com/braintrustdata/braintrust-kotlin/commit/a82733e731582a7b7a3e71c08cc06bae9be394e6)) +* update singularization rules ([772887c](https://github.com/braintrustdata/braintrust-kotlin/commit/772887c2a2e904850458aaf0179b1f947ea8e68a)) + + +### Performance Improvements + +* **client:** cached parsed type in `HttpResponseFor` ([#147](https://github.com/braintrustdata/braintrust-kotlin/issues/147)) ([be273d1](https://github.com/braintrustdata/braintrust-kotlin/commit/be273d1bc370a9ae55adb28f99ca9f317fcd9cfc)) +* **internal:** make formatting faster ([b8e05ea](https://github.com/braintrustdata/braintrust-kotlin/commit/b8e05ea9d384380e96d6aab61b78f76d4ad77e75)) + + +### Chores + +* **api:** manual updates ([#58](https://github.com/braintrustdata/braintrust-kotlin/issues/58)) ([a98c90c](https://github.com/braintrustdata/braintrust-kotlin/commit/a98c90c8a5e47b23a1346e3e5b476006011dc3e2)) +* **ci:** add build job ([aa79cc8](https://github.com/braintrustdata/braintrust-kotlin/commit/aa79cc8908b94e9971719b8ba55ba94ffdf676f6)) +* **ci:** add timeout thresholds for CI jobs ([a4be02a](https://github.com/braintrustdata/braintrust-kotlin/commit/a4be02a1cff356852fbcf9cf1e5bf793d2c39b70)) +* **ci:** bump `actions/setup-java` to v4 ([ae504a3](https://github.com/braintrustdata/braintrust-kotlin/commit/ae504a3bd6f6d1dd460f7954773d3d1b7ea35dce)) +* **ci:** enable for pull requests ([9883bd7](https://github.com/braintrustdata/braintrust-kotlin/commit/9883bd7f815d0fdb4a71d459dc9c707d5a32f2b8)) +* **ci:** ensure docs generation always succeeds ([53f3fde](https://github.com/braintrustdata/braintrust-kotlin/commit/53f3fde57d20a74c012aaa62cff4e73bd4660c94)) +* **ci:** only run for pushes and fork pull requests ([6fe433e](https://github.com/braintrustdata/braintrust-kotlin/commit/6fe433e3ce9ad421f6cbe36ea4b8e41b83d61ae3)) +* **ci:** only use depot for staging repos ([c32ff0c](https://github.com/braintrustdata/braintrust-kotlin/commit/c32ff0caa5ab4d523fe2e1d1132454e7ba8d4218)) +* **ci:** reduce log noise ([140ff0c](https://github.com/braintrustdata/braintrust-kotlin/commit/140ff0ccbb2e258ac933ec91c1bfe76df07aee6e)) +* **client:** refactor closing / shutdown ([96dc010](https://github.com/braintrustdata/braintrust-kotlin/commit/96dc01044da36ffca689356e2eb779627d0fad88)) +* **client:** refactor exception structure and methods ([#132](https://github.com/braintrustdata/braintrust-kotlin/issues/132)) ([d06a530](https://github.com/braintrustdata/braintrust-kotlin/commit/d06a530151dfb6acefe0f2ff8d2a3ca114a26d14)) +* **client:** refactor multipart formdata impl ([#99](https://github.com/braintrustdata/braintrust-kotlin/issues/99)) ([b6cd77a](https://github.com/braintrustdata/braintrust-kotlin/commit/b6cd77af8a9a2aa167cf6c029c4bdd2b414bcd7f)) +* **client:** remove unnecessary json state from some query param classes ([1e676fb](https://github.com/braintrustdata/braintrust-kotlin/commit/1e676fb297914ce740c8fea2708bc624585dad01)) +* **deps:** bump jackson to 2.18.1 ([#86](https://github.com/braintrustdata/braintrust-kotlin/issues/86)) ([95066db](https://github.com/braintrustdata/braintrust-kotlin/commit/95066dba9029f273b2b0697f7e5cdb44cf09fed0)) +* **docs:** grammar improvements ([149705f](https://github.com/braintrustdata/braintrust-kotlin/commit/149705f24b510a9f653bc20964499efd29498012)) +* **example:** fix run example comment ([5177a6e](https://github.com/braintrustdata/braintrust-kotlin/commit/5177a6edab59d77cc314590b118e0cc50c2837b2)) +* increase max gradle JVM heap to 8GB ([735ab96](https://github.com/braintrustdata/braintrust-kotlin/commit/735ab969460566d22647cb9d7e4b15add8bd95e1)) +* **internal:** add `.kotlin` to `.gitignore` ([#105](https://github.com/braintrustdata/braintrust-kotlin/issues/105)) ([3a73e2e](https://github.com/braintrustdata/braintrust-kotlin/commit/3a73e2ee0156e1a621de677cc4dd55e4bce61833)) +* **internal:** add generated comment ([#124](https://github.com/braintrustdata/braintrust-kotlin/issues/124)) ([3a85ba6](https://github.com/braintrustdata/braintrust-kotlin/commit/3a85ba64646c7fc3da1ffd1ae39ddc493a5fc458)) +* **internal:** add invalid json deserialization tests ([1e676fb](https://github.com/braintrustdata/braintrust-kotlin/commit/1e676fb297914ce740c8fea2708bc624585dad01)) +* **internal:** add json roundtripping tests ([1e676fb](https://github.com/braintrustdata/braintrust-kotlin/commit/1e676fb297914ce740c8fea2708bc624585dad01)) +* **internal:** add lock helper ([1bfeedd](https://github.com/braintrustdata/braintrust-kotlin/commit/1bfeeddc0f9c3db43ffa8fb8f175168cac840878)) +* **internal:** add missing release please block ([#131](https://github.com/braintrustdata/braintrust-kotlin/issues/131)) ([73bca42](https://github.com/braintrustdata/braintrust-kotlin/commit/73bca42614d506179d61c1d07851f75334c02c17)) +* **internal:** add tests for `_headers()` ([#127](https://github.com/braintrustdata/braintrust-kotlin/issues/127)) ([37a409a](https://github.com/braintrustdata/braintrust-kotlin/commit/37a409a2b24f4c93f688dd71104a4dd2c40fed6d)) +* **internal:** allow running specific example from cli ([b685ffd](https://github.com/braintrustdata/braintrust-kotlin/commit/b685ffdb17dcea9fcd193cbac2eabfc708622d0f)) +* **internal:** bump ci test timeout ([cdb84ce](https://github.com/braintrustdata/braintrust-kotlin/commit/cdb84ce94258505395d6de7800cc971237339a07)) +* **internal:** codegen related update ([c842666](https://github.com/braintrustdata/braintrust-kotlin/commit/c842666eb2d3acd34b9ed4f17d3fa76dc9b6eb26)) +* **internal:** codegen related update ([a9f3ce0](https://github.com/braintrustdata/braintrust-kotlin/commit/a9f3ce024be5acefb194542199f0b4928bcc8343)) +* **internal:** codegen related update ([af659ea](https://github.com/braintrustdata/braintrust-kotlin/commit/af659eabb00d6fbe6edc1edb6394c30dd228c8da)) +* **internal:** codegen related update ([#110](https://github.com/braintrustdata/braintrust-kotlin/issues/110)) ([114138e](https://github.com/braintrustdata/braintrust-kotlin/commit/114138e9d321e29a46bcd951d40a2601b85b9416)) +* **internal:** codegen related update ([#111](https://github.com/braintrustdata/braintrust-kotlin/issues/111)) ([3632207](https://github.com/braintrustdata/braintrust-kotlin/commit/363220747d20629427c07b7d2825a4022749d935)) +* **internal:** codegen related update ([#112](https://github.com/braintrustdata/braintrust-kotlin/issues/112)) ([9a6b149](https://github.com/braintrustdata/braintrust-kotlin/commit/9a6b1490e83543617f6dbe78e0e7b2b5a3231570)) +* **internal:** codegen related update ([#113](https://github.com/braintrustdata/braintrust-kotlin/issues/113)) ([29c3842](https://github.com/braintrustdata/braintrust-kotlin/commit/29c3842d83027fb676c808db33862310f278a2bb)) +* **internal:** codegen related update ([#114](https://github.com/braintrustdata/braintrust-kotlin/issues/114)) ([9d96723](https://github.com/braintrustdata/braintrust-kotlin/commit/9d96723dc8c74ff28fbbbc0821a63a10ce1248ba)) +* **internal:** codegen related update ([#115](https://github.com/braintrustdata/braintrust-kotlin/issues/115)) ([e471285](https://github.com/braintrustdata/braintrust-kotlin/commit/e471285b4c1bed4d8d9942340059a35ec18b823b)) +* **internal:** codegen related update ([#134](https://github.com/braintrustdata/braintrust-kotlin/issues/134)) ([942c135](https://github.com/braintrustdata/braintrust-kotlin/commit/942c135e6b5a7753c820b075689497eff56b9261)) +* **internal:** codegen related update ([#146](https://github.com/braintrustdata/braintrust-kotlin/issues/146)) ([e31b6eb](https://github.com/braintrustdata/braintrust-kotlin/commit/e31b6ebf389ab55e60ebb6c54b5655ac6287eb72)) +* **internal:** codegen related update ([#87](https://github.com/braintrustdata/braintrust-kotlin/issues/87)) ([58407f3](https://github.com/braintrustdata/braintrust-kotlin/commit/58407f3b10ed5cd4ba69b9b906cd87a3cbb3d79f)) +* **internal:** codegen related update ([#88](https://github.com/braintrustdata/braintrust-kotlin/issues/88)) ([e2385b2](https://github.com/braintrustdata/braintrust-kotlin/commit/e2385b2a3059526106171a29f818da8fb8e7f60a)) +* **internal:** codegen related update ([#89](https://github.com/braintrustdata/braintrust-kotlin/issues/89)) ([7a1838c](https://github.com/braintrustdata/braintrust-kotlin/commit/7a1838c0a824aa4fa48e1948dc2d6dd3a02dad38)) +* **internal:** codegen related update ([#95](https://github.com/braintrustdata/braintrust-kotlin/issues/95)) ([40ba4ff](https://github.com/braintrustdata/braintrust-kotlin/commit/40ba4ff8f243db6e3bd996fd3a2e1e7fcfd51dd5)) +* **internal:** delete unused methods and annotations ([#138](https://github.com/braintrustdata/braintrust-kotlin/issues/138)) ([0092e84](https://github.com/braintrustdata/braintrust-kotlin/commit/0092e8412d90c313cf74c739e47e757ea97dca26)) +* **internal:** dynamically determine included projects ([d7375bb](https://github.com/braintrustdata/braintrust-kotlin/commit/d7375bbcf4e6ee994e20a613d1931c2880b111f6)) +* **internal:** expand CI branch coverage ([ebd3cbe](https://github.com/braintrustdata/braintrust-kotlin/commit/ebd3cbefe045a1277650170b8409ba41182a4c2a)) +* **internal:** generate more tests ([21aff2b](https://github.com/braintrustdata/braintrust-kotlin/commit/21aff2bf59c9f67d8873318c6f2af6459acd1c04)) +* **internal:** java 17 -> 21 on ci ([7908cfe](https://github.com/braintrustdata/braintrust-kotlin/commit/7908cfe2a370cc23c281710bfae4f8a89905c170)) +* **internal:** make multipart assertions more robust ([1c4b313](https://github.com/braintrustdata/braintrust-kotlin/commit/1c4b313004a2402143fc10e8f2798339ae2ea22f)) +* **internal:** make test classes internal ([#123](https://github.com/braintrustdata/braintrust-kotlin/issues/123)) ([ed8cb24](https://github.com/braintrustdata/braintrust-kotlin/commit/ed8cb24750ed69a822188d1d05667c4b19de76d2)) +* **internal:** reduce CI branch coverage ([34931ed](https://github.com/braintrustdata/braintrust-kotlin/commit/34931ed4b367ff26f45e92aadd0d9c94334a2a9e)) +* **internal:** reduce proguard ci logging ([d9e31bd](https://github.com/braintrustdata/braintrust-kotlin/commit/d9e31bdc655ad95080a9e99abbc84c9d75bce01f)) +* **internal:** reenable warnings as errors ([#106](https://github.com/braintrustdata/braintrust-kotlin/issues/106)) ([a2ece91](https://github.com/braintrustdata/braintrust-kotlin/commit/a2ece9177007f86fdfb625b971adc0bab1f21fd2)) +* **internal:** refactor `ErrorHandlingTest` ([#96](https://github.com/braintrustdata/braintrust-kotlin/issues/96)) ([4ca424c](https://github.com/braintrustdata/braintrust-kotlin/commit/4ca424c0d4961d2dea99c5b7e97a83416413364c)) +* **internal:** refactor delegating from client to options ([6a172fb](https://github.com/braintrustdata/braintrust-kotlin/commit/6a172fb0b958cab0b5dac3045f414afc44f3b865)) +* **internal:** refactor enum query param serialization ([#130](https://github.com/braintrustdata/braintrust-kotlin/issues/130)) ([0f12e8a](https://github.com/braintrustdata/braintrust-kotlin/commit/0f12e8aad758e7c59c5081a9a654dce96ce4df0d)) +* **internal:** refactor query param serialization impl and tests ([#126](https://github.com/braintrustdata/braintrust-kotlin/issues/126)) ([9fcd889](https://github.com/braintrustdata/braintrust-kotlin/commit/9fcd889f1e613deb236122807286e547339043ca)) +* **internal:** reformat some tests ([#128](https://github.com/braintrustdata/braintrust-kotlin/issues/128)) ([21aff2b](https://github.com/braintrustdata/braintrust-kotlin/commit/21aff2bf59c9f67d8873318c6f2af6459acd1c04)) +* **internal:** remove extra empty newlines ([#116](https://github.com/braintrustdata/braintrust-kotlin/issues/116)) ([461eeda](https://github.com/braintrustdata/braintrust-kotlin/commit/461eedaf86f21962accfaaf78b799385edbc9dfe)) +* **internal:** remove flaky `-Xbackend-threads=0` option ([0ea5d66](https://github.com/braintrustdata/braintrust-kotlin/commit/0ea5d665dd7731e1b5bef3cf4f2bd81dd6698551)) +* **internal:** remove unnecessary `[...]` in `[@see](https://github.com/see)` ([8199199](https://github.com/braintrustdata/braintrust-kotlin/commit/8199199658d0beffe0b98113a7e4833333a7608c)) +* **internal:** remove unnecessary `assertNotNull` calls ([1c4b313](https://github.com/braintrustdata/braintrust-kotlin/commit/1c4b313004a2402143fc10e8f2798339ae2ea22f)) +* **internal:** support passing arguments to test script ([a06c26e](https://github.com/braintrustdata/braintrust-kotlin/commit/a06c26e7fd6fc43a2ccbdc2bc0fcbb8f34d44167)) +* **internal:** support running ktfmt directly ([08b97d9](https://github.com/braintrustdata/braintrust-kotlin/commit/08b97d9f8e5371a1988aff367e1510a0e1c30e80)) +* **internal:** swap from `Builder().from(...)` to `toBuilder()` ([#139](https://github.com/braintrustdata/braintrust-kotlin/issues/139)) ([824e27f](https://github.com/braintrustdata/braintrust-kotlin/commit/824e27fa96754290044bddc887d8a5ea7a85c84c)) +* **internal:** update comment in script ([0804ff2](https://github.com/braintrustdata/braintrust-kotlin/commit/0804ff2024c349c6fd690c9091c855b0da03841a)) +* **internal:** update java toolchain ([e419cef](https://github.com/braintrustdata/braintrust-kotlin/commit/e419cef730c32bcee83a84fe01c50af6189cf8a1)) +* **internal:** update variable names in tests ([#107](https://github.com/braintrustdata/braintrust-kotlin/issues/107)) ([9517ac1](https://github.com/braintrustdata/braintrust-kotlin/commit/9517ac1f7ae0701dbae774827c6dc6bea0d1c04d)) +* minor change to tests ([#93](https://github.com/braintrustdata/braintrust-kotlin/issues/93)) ([5195a03](https://github.com/braintrustdata/braintrust-kotlin/commit/5195a030d173f78025f78c2fd0295db6a12e131f)) +* rebuild project due to codegen change ([#55](https://github.com/braintrustdata/braintrust-kotlin/issues/55)) ([1aff44c](https://github.com/braintrustdata/braintrust-kotlin/commit/1aff44cfbfdf19e35476dfcb7734aaa3eb00c2b0)) +* rebuild project due to codegen change ([#56](https://github.com/braintrustdata/braintrust-kotlin/issues/56)) ([e16106b](https://github.com/braintrustdata/braintrust-kotlin/commit/e16106b4164c1a8a3dc854c30582880cbbcf1169)) +* rebuild project due to codegen change ([#57](https://github.com/braintrustdata/braintrust-kotlin/issues/57)) ([3a5fc1c](https://github.com/braintrustdata/braintrust-kotlin/commit/3a5fc1c9ac893651cbf5406df0b00af745f9665a)) +* rebuild project due to codegen change ([#59](https://github.com/braintrustdata/braintrust-kotlin/issues/59)) ([fe5e454](https://github.com/braintrustdata/braintrust-kotlin/commit/fe5e454a393ebf9d3b0116a7490227b2541a4be0)) +* rebuild project due to codegen change ([#60](https://github.com/braintrustdata/braintrust-kotlin/issues/60)) ([619fdf9](https://github.com/braintrustdata/braintrust-kotlin/commit/619fdf9e456883166f7a89e9bc4c1f2f7dc794db)) +* rebuild project due to codegen change ([#61](https://github.com/braintrustdata/braintrust-kotlin/issues/61)) ([34224b4](https://github.com/braintrustdata/braintrust-kotlin/commit/34224b4930331a004fa40bd8f15b06403e428ab3)) +* rebuild project due to codegen change ([#62](https://github.com/braintrustdata/braintrust-kotlin/issues/62)) ([8d3804c](https://github.com/braintrustdata/braintrust-kotlin/commit/8d3804cb4621d80e7f1c09b89958f14f6dbf0457)) +* rebuild project due to codegen change ([#63](https://github.com/braintrustdata/braintrust-kotlin/issues/63)) ([e941f87](https://github.com/braintrustdata/braintrust-kotlin/commit/e941f87250538b188c968eb867c90005f5880fbb)) +* rebuild project due to codegen change ([#64](https://github.com/braintrustdata/braintrust-kotlin/issues/64)) ([5b393df](https://github.com/braintrustdata/braintrust-kotlin/commit/5b393df9ff5ee7892e918ee67586c34a567c8adc)) +* rebuild project due to codegen change ([#65](https://github.com/braintrustdata/braintrust-kotlin/issues/65)) ([c86f18b](https://github.com/braintrustdata/braintrust-kotlin/commit/c86f18b700d39b94e0eedca6cad824b78de1a7ca)) +* rebuild project due to codegen change ([#66](https://github.com/braintrustdata/braintrust-kotlin/issues/66)) ([ffdfb6b](https://github.com/braintrustdata/braintrust-kotlin/commit/ffdfb6bbb0c7220349db6f14ff917f29a4087ce8)) +* rebuild project due to codegen change ([#67](https://github.com/braintrustdata/braintrust-kotlin/issues/67)) ([ba8f527](https://github.com/braintrustdata/braintrust-kotlin/commit/ba8f527856a7481bffd1f6790e9cc4de316f1545)) +* rebuild project due to codegen change ([#68](https://github.com/braintrustdata/braintrust-kotlin/issues/68)) ([d852b92](https://github.com/braintrustdata/braintrust-kotlin/commit/d852b923a2fb1b899c075ec39df795d761c49c07)) +* rebuild project due to codegen change ([#69](https://github.com/braintrustdata/braintrust-kotlin/issues/69)) ([7a303e4](https://github.com/braintrustdata/braintrust-kotlin/commit/7a303e4b9f87fac3385fdfc235bd69d8ee85827b)) +* rebuild project due to codegen change ([#71](https://github.com/braintrustdata/braintrust-kotlin/issues/71)) ([f7b50d0](https://github.com/braintrustdata/braintrust-kotlin/commit/f7b50d0e40a1df306fe8af6471ff6f22ae59809e)) +* rebuild project due to codegen change ([#73](https://github.com/braintrustdata/braintrust-kotlin/issues/73)) ([d08c8b7](https://github.com/braintrustdata/braintrust-kotlin/commit/d08c8b7eb735eaf67bceee775f5e665b9a3fca83)) +* rebuild project due to codegen change ([#74](https://github.com/braintrustdata/braintrust-kotlin/issues/74)) ([2ac019c](https://github.com/braintrustdata/braintrust-kotlin/commit/2ac019c76046e620a2f4096655e026855ce1d1ee)) +* rebuild project due to codegen change ([#78](https://github.com/braintrustdata/braintrust-kotlin/issues/78)) ([f067007](https://github.com/braintrustdata/braintrust-kotlin/commit/f067007eabed1a85b1e12ed451d830403de6da70)) +* remove memory upper bound from publishing step ([ad903a2](https://github.com/braintrustdata/braintrust-kotlin/commit/ad903a2ba07c510348634c003f70e5a84b2edc6e)) +* update @stainless-api/prism-cli to v5.15.0 ([08cdbb1](https://github.com/braintrustdata/braintrust-kotlin/commit/08cdbb14f4fde152a4c53ab41820426fef89c0ef)) + + +### Documentation + +* add `build` method comments ([#125](https://github.com/braintrustdata/braintrust-kotlin/issues/125)) ([54c75b9](https://github.com/braintrustdata/braintrust-kotlin/commit/54c75b923c8bb9a048d26fd31872444b0bea081a)) +* add comments for page methods ([71968b4](https://github.com/braintrustdata/braintrust-kotlin/commit/71968b4109ba33d824a9dbdf7567aa90b7b0ff6a)) +* add comments to `JsonField` classes ([#148](https://github.com/braintrustdata/braintrust-kotlin/issues/148)) ([a53cd38](https://github.com/braintrustdata/braintrust-kotlin/commit/a53cd383e1f5b66a7c98fdab5c045eefc667c82a)) +* add more phantom reachability docs ([#94](https://github.com/braintrustdata/braintrust-kotlin/issues/94)) ([15a955a](https://github.com/braintrustdata/braintrust-kotlin/commit/15a955a5a502aa4c0ec830997b118c5d8a485bd0)) +* add raw response readme documentation ([#100](https://github.com/braintrustdata/braintrust-kotlin/issues/100)) ([4c488b8](https://github.com/braintrustdata/braintrust-kotlin/commit/4c488b803b1f69cb409eb6c1214d6723997381ce)) +* **client:** update jackson compat error message ([586f861](https://github.com/braintrustdata/braintrust-kotlin/commit/586f86117cf81cffec6f64e11694057cad325ae2)) +* deduplicate and refine comments ([#122](https://github.com/braintrustdata/braintrust-kotlin/issues/122)) ([a47e6a6](https://github.com/braintrustdata/braintrust-kotlin/commit/a47e6a6e57c7250986794b6808ec46500a49c370)) +* document `JsonValue` construction in readme ([#109](https://github.com/braintrustdata/braintrust-kotlin/issues/109)) ([11b3017](https://github.com/braintrustdata/braintrust-kotlin/commit/11b3017071384e9e36281492721fdf88b7027687)) +* document how to forcibly omit required field ([d1d2b4e](https://github.com/braintrustdata/braintrust-kotlin/commit/d1d2b4e30df7530fbaf0fd8abdc67a17ea08314d)) +* explain http client customization ([d19552a](https://github.com/braintrustdata/braintrust-kotlin/commit/d19552a231d1dde19da4a7f25c8e0b763df67cab)) +* explain jackson compat in readme ([0855121](https://github.com/braintrustdata/braintrust-kotlin/commit/085512167b07d63932bcddb8266a762c416d58c7)) +* fix missing readme comment ([32b005b](https://github.com/braintrustdata/braintrust-kotlin/commit/32b005bce1c7cba24af587f1ec39e26cf2aa9e89)) +* minor readme tweak ([#136](https://github.com/braintrustdata/braintrust-kotlin/issues/136)) ([d802340](https://github.com/braintrustdata/braintrust-kotlin/commit/d80234046327fae20d37c79bc97a62b3fc91d751)) +* more code comments ([869771b](https://github.com/braintrustdata/braintrust-kotlin/commit/869771b2a3cc93d84baf4c25590f5c70ef994733)) +* note required fields in `builder` javadoc ([#101](https://github.com/braintrustdata/braintrust-kotlin/issues/101)) ([fac37c4](https://github.com/braintrustdata/braintrust-kotlin/commit/fac37c454be319939a43b52f89fe259768214b11)) +* refine comments on multipart params ([#133](https://github.com/braintrustdata/braintrust-kotlin/issues/133)) ([1c4b313](https://github.com/braintrustdata/braintrust-kotlin/commit/1c4b313004a2402143fc10e8f2798339ae2ea22f)) +* remove `$` for better copy-pasteabality ([9fbdb0d](https://github.com/braintrustdata/braintrust-kotlin/commit/9fbdb0dd607df02472c5b515b4dbb8183ace8661)) +* revise readme docs about nested params ([#108](https://github.com/braintrustdata/braintrust-kotlin/issues/108)) ([6c4a081](https://github.com/braintrustdata/braintrust-kotlin/commit/6c4a081468757ffa6e2e6039b90772691e19ef3a)) +* swap examples used in readme ([#149](https://github.com/braintrustdata/braintrust-kotlin/issues/149)) ([d1d2b4e](https://github.com/braintrustdata/braintrust-kotlin/commit/d1d2b4e30df7530fbaf0fd8abdc67a17ea08314d)) +* update documentation links to be more uniform ([8d54da2](https://github.com/braintrustdata/braintrust-kotlin/commit/8d54da2dd7d3489cef999e28dabb8fd1437bca56)) +* update readme exception docs ([#135](https://github.com/braintrustdata/braintrust-kotlin/issues/135)) ([cedf2ce](https://github.com/braintrustdata/braintrust-kotlin/commit/cedf2ce2a6a26f6c0ef5b43771e42f8ef214bdd1)) + + +### Refactors + +* **client:** deduplicate page response classes ([71968b4](https://github.com/braintrustdata/braintrust-kotlin/commit/71968b4109ba33d824a9dbdf7567aa90b7b0ff6a)) +* **client:** migrate pages to builder pattern ([2113261](https://github.com/braintrustdata/braintrust-kotlin/commit/21132614bb49582679dfddbfa7c631bd80b44d00)) +* **internal:** minor `ClientOptionsTest` change ([151c8eb](https://github.com/braintrustdata/braintrust-kotlin/commit/151c8eba64ad1bc5e4232bb9afad4b36655cb197)) + ## 0.3.0 (2024-10-01) Full Changelog: [v0.2.0...v0.3.0](https://github.com/braintrustdata/braintrust-kotlin/compare/v0.2.0...v0.3.0) diff --git a/LICENSE b/LICENSE index 5e03e95a..f3b9e7e5 100755 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Braintrust + Copyright 2025 Braintrust 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 6c189717..5568a08c 100644 --- a/README.md +++ b/README.md @@ -1,241 +1,351 @@ # Braintrust Kotlin API Library -The Braintrust Kotlin SDK provides convenient access to the Braintrust REST API from applications written in Kotlin. It includes helper classes with helpful types and documentation for every request and response property. + -The Braintrust Kotlin SDK is similar to the Braintrust Java SDK but with minor differences that make it more ergonomic for use in Kotlin, such as nullable values instead of `Optional`, `Sequence` instead of `Stream`, and suspend functions instead of `CompletableFuture`. +[![Maven Central](https://img.shields.io/maven-central/v/com.braintrustdata.api/braintrust-kotlin)](https://central.sonatype.com/artifact/com.braintrustdata.api/braintrust-kotlin/0.4.0) +[![javadoc](https://javadoc.io/badge2/com.braintrustdata.api/braintrust-kotlin/0.4.0/javadoc.svg)](https://javadoc.io/doc/com.braintrustdata.api/braintrust-kotlin/0.4.0) -It is generated with [Stainless](https://www.stainlessapi.com/). + -## Documentation +The Braintrust Kotlin SDK provides convenient access to the [Braintrust REST API](https://www.braintrustdata.com/docs/api/spec) from applications written in Kotlin. -The REST API documentation can be found on [www.braintrustdata.com](https://www.braintrustdata.com/docs/api/spec). +The Braintrust Kotlin SDK is similar to the Braintrust Java SDK but with minor differences that make it more ergonomic for use in Kotlin, such as nullable values instead of `Optional`, `Sequence` instead of `Stream`, and suspend functions instead of `CompletableFuture`. ---- +It is generated with [Stainless](https://www.stainless.com/). -## Getting started + + +The REST API documentation can be found on [www.braintrustdata.com](https://www.braintrustdata.com/docs/api/spec). KDocs are available on [javadoc.io](https://javadoc.io/doc/com.braintrustdata.api/braintrust-kotlin/0.4.0). -### Install dependencies + -#### Gradle +## Installation +### Gradle + ```kotlin -implementation("com.braintrustdata.api:braintrust-kotlin:0.3.0") +implementation("com.braintrustdata.api:braintrust-kotlin:0.4.0") ``` -#### Maven +### Maven ```xml - com.braintrustdata.api - braintrust-kotlin - 0.3.0 + com.braintrustdata.api + braintrust-kotlin + 0.4.0 ``` -### Configure the client +## Requirements -Use `BraintrustOkHttpClient.builder()` to configure the client. +This library requires Java 8 or later. -Alternately, set the environment with `BRAINTRUST_API_KEY`, and use `BraintrustOkHttpClient.fromEnv()` to read from the environment. +## Usage ```kotlin -val client = BraintrustOkHttpClient.fromEnv() +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient +import com.braintrustdata.api.models.Project +import com.braintrustdata.api.models.ProjectCreateParams -// Note: you can also call fromEnv() from the client builder, for example if you need to set additional properties -val client = BraintrustOkHttpClient.builder() - .fromEnv() - // ... set properties on the builder +// Configures using the `braintrust.apiKey` and `braintrust.baseUrl` system properties +// Or configures using the `BRAINTRUST_API_KEY` and `BRAINTRUST_BASE_URL` environment variables +val client: BraintrustClient = BraintrustOkHttpClient.fromEnv() + +val params: ProjectCreateParams = ProjectCreateParams.builder() + .name("foobar") .build() +val project: Project = client.projects().create(params) ``` -| Property | Environment variable | Required | Default value | -| -------- | -------------------- | -------- | ------------- | -| apiKey | `BRAINTRUST_API_KEY` | false | — | +## Client configuration -Read the documentation for more configuration options. +Configure the client using system properties or environment variables: ---- +```kotlin +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -### Example: creating a resource +// Configures using the `braintrust.apiKey` and `braintrust.baseUrl` system properties +// Or configures using the `BRAINTRUST_API_KEY` and `BRAINTRUST_BASE_URL` environment variables +val client: BraintrustClient = BraintrustOkHttpClient.fromEnv() +``` -To create a new project, first use the `ProjectCreateParams` builder to specify attributes, -then pass that to the `create` method of the `projects` service. +Or manually: ```kotlin -import com.braintrustdata.api.models.Project -import com.braintrustdata.api.models.ProjectCreateParams +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -val params = ProjectCreateParams.builder() - .name("foobar") +val client: BraintrustClient = BraintrustOkHttpClient.builder() + .apiKey("My API Key") + .build() +``` + +Or using a combination of the two approaches: + +```kotlin +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient + +val client: BraintrustClient = BraintrustOkHttpClient.builder() + // Configures using the `braintrust.apiKey` and `braintrust.baseUrl` system properties + // Or configures using the `BRAINTRUST_API_KEY` and `BRAINTRUST_BASE_URL` environment variables + .fromEnv() + .apiKey("My API Key") .build() -val project = client.projects().create(params) ``` -### Example: listing resources +See this table for the available options: + +| Setter | System property | Environment variable | Required | Default value | +| --------- | -------------------- | --------------------- | -------- | ------------------------------ | +| `apiKey` | `braintrust.apiKey` | `BRAINTRUST_API_KEY` | false | - | +| `baseUrl` | `braintrust.baseUrl` | `BRAINTRUST_BASE_URL` | true | `"https://api.braintrust.dev"` | + +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. -The Braintrust API provides a `list` method to get a paginated list of projects. -You can retrieve the first page by: +### Modifying configuration + +To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service: ```kotlin -import com.braintrustdata.api.models.Page -import com.braintrustdata.api.models.Project +import com.braintrustdata.api.client.BraintrustClient -val page = client.projects().list() -for (project: Project in page.objects()) { - print(project) +val clientWithOptions: BraintrustClient = client.withOptions { + it.baseUrl("https://example.com") + it.maxRetries(42) } ``` -See [Pagination](#pagination) below for more information on transparently working with lists of objects without worrying about fetching each page. +The `withOptions()` method does not affect the original client or service. + +## Requests and responses ---- +To send a request to the Braintrust 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 Kotlin class. -## Requests +For example, `client.projects().create(...)` should be called with an instance of `ProjectCreateParams`, and it will return an instance of `Project`. -### Parameters and bodies +## Immutability -To make a request to the Braintrust API, you generally build an instance of the appropriate `Params` class. +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. -In [Example: creating a resource](#example-creating-a-resource) above, we used the `ProjectCreateParams.builder()` to pass to -the `create` method of the `projects` service. +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. -Sometimes, the API may support other properties that are not yet supported in the Kotlin SDK types. In that case, -you can attach them using the `putAdditionalProperty` method. +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: ```kotlin -import com.braintrustdata.api.models.core.JsonValue -val params = ProjectCreateParams.builder() - // ... normal properties - .putAdditionalProperty("secret_param", JsonValue.from("4242")) +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient +import com.braintrustdata.api.models.Project +import com.braintrustdata.api.models.ProjectCreateParams + +// Configures using the `braintrust.apiKey` and `braintrust.baseUrl` system properties +// Or configures using the `BRAINTRUST_API_KEY` and `BRAINTRUST_BASE_URL` environment variables +val client: BraintrustClient = BraintrustOkHttpClient.fromEnv() + +val params: ProjectCreateParams = ProjectCreateParams.builder() + .name("foobar") .build() +val project: Project = client.async().projects().create(params) ``` -## Responses +Or create an asynchronous client from the beginning: -### Response validation +```kotlin +import com.braintrustdata.api.client.BraintrustClientAsync +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.Project +import com.braintrustdata.api.models.ProjectCreateParams -When receiving a response, the Braintrust Kotlin SDK will deserialize it into instances of the typed model classes. In rare cases, the API may return a response property that doesn't match the expected Kotlin type. If you directly access the mistaken property, the SDK will throw an unchecked `BraintrustInvalidDataException` at runtime. If you would prefer to check in advance that that response is completely well-typed, call `.validate()` on the returned model. +// Configures using the `braintrust.apiKey` and `braintrust.baseUrl` system properties +// Or configures using the `BRAINTRUST_API_KEY` and `BRAINTRUST_BASE_URL` environment variables +val client: BraintrustClientAsync = BraintrustOkHttpClientAsync.fromEnv() -```kotlin -val project = client.projects().create().validate() +val params: ProjectCreateParams = ProjectCreateParams.builder() + .name("foobar") + .build() +val project: Project = client.projects().create(params) ``` -### Response properties as JSON +The asynchronous client supports the same options as the synchronous one, except most methods are [suspending](https://kotlinlang.org/docs/coroutines-guide.html). + +## Raw responses + +The SDK defines methods that deserialize responses into instances of Kotlin classes. However, these methods don't provide access to the response headers, status code, or the raw response body. -In rare cases, you may want to access the underlying JSON value for a response property rather than using the typed version provided by -this SDK. Each model property has a corresponding JSON version, with an underscore before the method name, which returns a `JsonField` value. +To access this data, prefix any HTTP method call on a client or service with `withRawResponse()`: ```kotlin -val field = responseObj._field +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.models.Project +import com.braintrustdata.api.models.ProjectCreateParams -if (field.isMissing()) { - // Value was not specified in the JSON response -} else if (field.isNull()) { - // Value was provided as a literal null -} else { - // See if value was provided as a string - val jsonString: String? = field.asString(); +val params: ProjectCreateParams = ProjectCreateParams.builder() + .name("foobar") + .build() +val project: HttpResponseFor = client.projects().withRawResponse().create(params) - // If the value given by the API did not match the shape that the SDK expects - // you can deserialise into a custom type - val myObj = responseObj._field.asUnknown()?.convert(MyClass.class) -} +val statusCode: Int = project.statusCode() +val headers: Headers = project.headers() ``` -### Additional model properties - -Sometimes, the server response may include additional properties that are not yet available in this library's types. You can access them using the model's `_additionalProperties` method: +You can still deserialize the response into an instance of a Kotlin class if needed: ```kotlin -val secret = aISecret._additionalProperties().get("secret_field") +import com.braintrustdata.api.models.Project + +val parsedProject: Project = project.parse() ``` ---- +## Error handling + +The SDK throws custom unchecked exception types: + +- [`BraintrustServiceException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: + + | Status | Exception | + | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- | + | 400 | [`BadRequestException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BadRequestException.kt) | + | 401 | [`UnauthorizedException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnauthorizedException.kt) | + | 403 | [`PermissionDeniedException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/PermissionDeniedException.kt) | + | 404 | [`NotFoundException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/NotFoundException.kt) | + | 422 | [`UnprocessableEntityException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnprocessableEntityException.kt) | + | 429 | [`RateLimitException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/RateLimitException.kt) | + | 5xx | [`InternalServerException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/InternalServerException.kt) | + | others | [`UnexpectedStatusCodeException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnexpectedStatusCodeException.kt) | + +- [`BraintrustIoException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustIoException.kt): I/O networking errors. + +- [`BraintrustRetryableException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustRetryableException.kt): Generic error indicating a failure that could be retried by the client. + +- [`BraintrustInvalidDataException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustInvalidDataException.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. + +- [`BraintrustException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustException.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. ## Pagination -For methods that return a paginated list of results, this library provides convenient ways access -the results either one page at a time, or item-by-item across all pages. +The SDK defines methods that return a paginated lists of results. It provides convenient ways to access the results either one page at a time or item-by-item across all pages. ### Auto-pagination -To iterate through all results across all pages, you can use `autoPager`, -which automatically handles fetching more pages for you: +To iterate through all results across all pages, use the `autoPager()` method, which automatically fetches more pages as needed. -### Synchronous +When using the synchronous client, the method returns a [`Sequence`](https://kotlinlang.org/docs/sequences.html) ```kotlin -// As a Sequence: -client.projects().list(params).autoPager() +import com.braintrustdata.api.models.ProjectListPage + +val page: ProjectListPage = client.projects().list() +page.autoPager() .take(50) - .forEach { project -> print(project) } + .forEach { project -> println(project) } ``` -### Asynchronous +When using the asynchronous client, the method returns a [`Flow`](https://kotlinlang.org/docs/flow.html): ```kotlin -// As a Flow: -asyncClient.projects().list(params).autoPager() +import com.braintrustdata.api.models.ProjectListPageAsync + +val page: ProjectListPageAsync = client.async().projects().list() +page.autoPager() .take(50) - .collect { project -> print(project) } + .forEach { project -> println(project) } ``` ### Manual pagination -If none of the above helpers meet your needs, you can also manually request pages one-by-one. -A page of results has a `data()` method to fetch the list of objects, as well as top-level -`response` and other methods to fetch top-level data about the page. It also has methods -`hasNextPage`, `getNextPage`, and `getNextPageParams` methods to help with pagination. +To access individual page items and manually request the next page, use the `items()`, +`hasNextPage()`, and `nextPage()` methods: ```kotlin -val page = client.projects().list(params) -while (page != null) { - for (project in page.objects) { - print(project) +import com.braintrustdata.api.models.Project +import com.braintrustdata.api.models.ProjectListPage + +val page: ProjectListPage = client.projects().list() +while (true) { + for (project in page.items()) { + println(project) + } + + if (!page.hasNextPage()) { + break } - page = page.getNextPage() + page = page.nextPage() } ``` ---- +## Logging -## Error handling +The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor). + +Enable logging by setting the `BRAINTRUST_LOG` environment variable to `info`: + +```sh +export BRAINTRUST_LOG=info +``` + +Or to `debug` for more verbose logging: -This library throws exceptions in a single hierarchy for easy handling: +```sh +export BRAINTRUST_LOG=debug +``` -- **`BraintrustException`** - Base exception for all exceptions +## ProGuard and R8 - - **`BraintrustServiceException`** - HTTP errors with a well-formed response body we were able to parse. The exception message and the `.debuggingRequestId()` will be set by the server. +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 `braintrust-kotlin-core` is published with a [configuration file](braintrust-kotlin-core/src/main/resources/META-INF/proguard/braintrust-kotlin-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). - | 400 | BadRequestException | - | ------ | ----------------------------- | - | 401 | AuthenticationException | - | 403 | PermissionDeniedException | - | 404 | NotFoundException | - | 422 | UnprocessableEntityException | - | 429 | RateLimitException | - | 5xx | InternalServerException | - | others | UnexpectedStatusCodeException | +ProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary. - - **`BraintrustIoException`** - I/O networking errors - - **`BraintrustInvalidDataException`** - any other exceptions on the client side, e.g.: - - We failed to serialize the request body - - We failed to parse the response body (has access to response code and body) +## 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 [`BraintrustOkHttpClient`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt) or [`BraintrustOkHttpClientAsync`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.kt). + +> [!CAUTION] +> We make no guarantee that the SDK works correctly when the Jackson version check is disabled. ## Network options ### Retries -Requests that experience certain errors are automatically retried 2 times by default, with a short exponential backoff. Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors will all be retried by default. -You can provide a `maxRetries` on the client builder to configure this: +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: ```kotlin -val client = BraintrustOkHttpClient.builder() +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient + +val client: BraintrustClient = BraintrustOkHttpClient.builder() .fromEnv() .maxRetries(4) .build() @@ -243,10 +353,26 @@ val client = BraintrustOkHttpClient.builder() ### Timeouts -Requests time out after 1 minute by default. You can configure this on the client builder: +Requests time out after 1 minute by default. + +To set a custom timeout, configure the method call using the `timeout` method: ```kotlin -val client = BraintrustOkHttpClient.builder() +import com.braintrustdata.api.models.Project + +val project: Project = client.projects().create( + params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() +) +``` + +Or configure the default for all method calls at the client level: + +```kotlin +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient +import java.time.Duration + +val client: BraintrustClient = BraintrustOkHttpClient.builder() .fromEnv() .timeout(Duration.ofSeconds(30)) .build() @@ -254,29 +380,292 @@ val client = BraintrustOkHttpClient.builder() ### Proxies -Requests can be routed through a proxy. You can configure this on the client builder: +To route requests through a proxy, configure the client using the `proxy` method: ```kotlin -val client = BraintrustOkHttpClient.builder() +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient +import java.net.InetSocketAddress +import java.net.Proxy + +val client: BraintrustClient = BraintrustOkHttpClient.builder() .fromEnv() - .proxy(new Proxy( - Type.HTTP, - new InetSocketAddress("proxy.com", 8080) + .proxy(Proxy( + Proxy.Type.HTTP, 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: + +```kotlin +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient + +val client: BraintrustClient = BraintrustOkHttpClient.builder() + .fromEnv() + // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa. + .sslSocketFactory(yourSSLSocketFactory) + .trustManager(yourTrustManager) + .hostnameVerifier(yourHostnameVerifier) + .build() +``` + +### Custom HTTP client + +The SDK consists of three artifacts: + +- `braintrust-kotlin-core` + - Contains core SDK logic + - Does not depend on [OkHttp](https://square.github.io/okhttp) + - Exposes [`BraintrustClient`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClient.kt), [`BraintrustClientAsync`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsync.kt), [`BraintrustClientImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt), and [`BraintrustClientAsyncImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt), all of which can work with any HTTP client +- `braintrust-kotlin-client-okhttp` + - Depends on [OkHttp](https://square.github.io/okhttp) + - Exposes [`BraintrustOkHttpClient`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt) and [`BraintrustOkHttpClientAsync`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.kt), which provide a way to construct [`BraintrustClientImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt) and [`BraintrustClientAsyncImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt), respectively, using OkHttp +- `braintrust-kotlin` + - Depends on and exposes the APIs of both `braintrust-kotlin-core` and `braintrust-kotlin-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 [`braintrust-kotlin` dependency](#installation) with `braintrust-kotlin-core` +2. Copy `braintrust-kotlin-client-okhttp`'s [`OkHttpClient`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/OkHttpClient.kt) class into your code and customize it +3. Construct [`BraintrustClientImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt) or [`BraintrustClientAsyncImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt), similarly to [`BraintrustOkHttpClient`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt) or [`BraintrustOkHttpClientAsync`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.kt), using your customized client + +### Completely custom HTTP client + +To use a completely custom HTTP client: + +1. Replace your [`braintrust-kotlin` dependency](#installation) with `braintrust-kotlin-core` +2. Write a class that implements the [`HttpClient`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpClient.kt) interface +3. Construct [`BraintrustClientImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt) or [`BraintrustClientAsyncImpl`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt), similarly to [`BraintrustOkHttpClient`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt) or [`BraintrustOkHttpClientAsync`](braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.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: + +```kotlin +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.ProjectCreateParams + +val params: ProjectCreateParams = ProjectCreateParams.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: + +```kotlin +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.ProjectSettings +import com.braintrustdata.api.models.ProjectUpdateParams + +val params: ProjectUpdateParams = ProjectUpdateParams.builder() + .settings(ProjectSettings.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`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Values.kt) object to its setter: + +```kotlin +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.ProjectCreateParams + +val params: ProjectCreateParams = ProjectCreateParams.builder() + .name(JsonValue.from(42)) + .build() +``` + +The most straightforward way to create a [`JsonValue`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Values.kt) is using its `from(...)` method: + +```kotlin +import com.braintrustdata.api.core.JsonValue + +// Create primitive JSON values +val nullValue: JsonValue = JsonValue.from(null) +val booleanValue: JsonValue = JsonValue.from(true) +val numberValue: JsonValue = JsonValue.from(42) +val stringValue: JsonValue = JsonValue.from("Hello World!") + +// Create a JSON array value equivalent to `["Hello", "World"]` +val arrayValue: JsonValue = JsonValue.from(listOf( + "Hello", "World" +)) + +// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }` +val objectValue: JsonValue = JsonValue.from(mapOf( + "a" to 1, "b" to 2 +)) + +// Create an arbitrarily nested JSON equivalent to: +// { +// "a": [1, 2], +// "b": [3, 4] +// } +val complexValue: JsonValue = JsonValue.from(mapOf( + "a" to listOf( + 1, 2 + ), "b" to listOf( + 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`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Values.kt): + +```kotlin +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.models.ProjectCreateParams + +val params: ProjectCreateParams = ProjectCreateParams.builder() + .name(JsonMissing.of()) + .build() +``` + +### Response properties + +To access undocumented response properties, call the `_additionalProperties()` method: + +```kotlin +import com.braintrustdata.api.core.JsonBoolean +import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonNumber +import com.braintrustdata.api.core.JsonValue + +val additionalProperties: Map = client.projects().create(params)._additionalProperties() +val secretPropertyValue: JsonValue = additionalProperties.get("secretProperty") + +val result = when (secretPropertyValue) { + is JsonNull -> "It's null!" + is JsonBoolean -> "It's a boolean!" + is JsonNumber -> "It's a number!" + // Other types include `JsonMissing`, `JsonString`, `JsonArray`, and `JsonObject` + else -> "It's something else!" +} +``` + +To access a property's raw JSON value, which may be undocumented, call its `_` prefixed method: + +```kotlin +import com.braintrustdata.api.core.JsonField + +val name: JsonField = client.projects().create(params)._name() + +if (name.isMissing()) { + // The property is absent from the JSON response +} else if (name.isNull()) { + // The property was set to literal null +} else { + // Check if value was provided as a string + // Other methods include `asNumber()`, `asBoolean()`, etc. + val jsonString: String? = name.asString(); + + // Try to deserialize into a custom type + val myObject: MyClass = name.asUnknown()!!.convert(MyClass::class.java) +} +``` + +### 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 [`BraintrustInvalidDataException`](braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustInvalidDataException.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()`: + +```kotlin +import com.braintrustdata.api.models.Project + +val project: Project = client.projects().create(params).validate() +``` + +Or configure the method call to validate the response using the `responseValidation` method: + +```kotlin +import com.braintrustdata.api.models.Project + +val project: Project = client.projects().create( + params, RequestOptions.builder().responseValidation(true).build() +) +``` + +Or configure the default for all method calls at the client level: + +```kotlin +import com.braintrustdata.api.client.BraintrustClient +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient + +val client: BraintrustClient = BraintrustOkHttpClient.builder() + .fromEnv() + .responseValidation(true) + .build() +``` + +## FAQ + +### Why don't you use plain `enum` classes? + +Kotlin `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)_. +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/braintrustdata/braintrust-kotlin/issues) with questions, bugs, or suggestions. - -## Requirements - -This library requires Java 8 or later. diff --git a/SECURITY.md b/SECURITY.md index 5702c21d..a7f4f3b4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,9 +2,9 @@ ## Reporting Security Issues -This SDK is generated by [Stainless Software Inc](http://stainlessapi.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. +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@stainlessapi.com. +To report a security issue, please contact the Stainless team at security@stainless.com. ## Responsible Disclosure @@ -16,11 +16,11 @@ 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 Braintrust please follow the respective company's security reporting guidelines. +or products provided by Braintrust, please follow the respective company's security reporting guidelines. ### Braintrust Terms and Policies -Please contact info-test@braintrustdata.com for any questions or concerns regarding security of our services. +Please contact info@braintrustdata.com for any questions or concerns regarding the security of our services. --- diff --git a/bin/check-release-environment b/bin/check-release-environment index cc9c2cd7..3a6a7b4a 100755 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,19 +3,19 @@ errors=() if [ -z "${SONATYPE_USERNAME}" ]; then - errors+=("The BRAINTRUST_SONATYPE_USERNAME secret has not been set. Please set it in either this repository's secrets or your organization secrets") + 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 BRAINTRUST_SONATYPE_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") + 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 BRAINTRUST_SONATYPE_GPG_SIGNING_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets") + 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 BRAINTRUST_SONATYPE_GPG_SIGNING_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") + 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[@]} diff --git a/braintrust-kotlin-client-okhttp/build.gradle.kts b/braintrust-kotlin-client-okhttp/build.gradle.kts index a489e8ed..5c830e0d 100755 --- a/braintrust-kotlin-client-okhttp/build.gradle.kts +++ b/braintrust-kotlin-client-okhttp/build.gradle.kts @@ -6,11 +6,10 @@ plugins { dependencies { api(project(":braintrust-kotlin-core")) - implementation("com.google.guava:guava:33.0.0-jre") implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") testImplementation(kotlin("test")) testImplementation("org.assertj:assertj-core:3.25.3") - testImplementation("org.slf4j:slf4j-simple:2.0.12") } diff --git a/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt b/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt index 4c7f0fac..45327e16 100755 --- a/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt +++ b/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClient.kt @@ -5,37 +5,180 @@ package com.braintrustdata.api.client.okhttp import com.braintrustdata.api.client.BraintrustClient import com.braintrustdata.api.client.BraintrustClientImpl import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.core.Sleeper +import com.braintrustdata.api.core.Timeout +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.HttpClient +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.jsonMapper import com.fasterxml.jackson.databind.json.JsonMapper import java.net.Proxy import java.time.Clock import java.time.Duration +import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager +/** + * A class that allows building an instance of [BraintrustClient] with [OkHttpClient] as the + * underlying [HttpClient]. + */ class BraintrustOkHttpClient private constructor() { companion object { + /** Returns a mutable builder for constructing an instance of [BraintrustClient]. */ fun builder() = Builder() + /** + * Returns a client configured using system properties and environment variables. + * + * @see ClientOptions.Builder.fromEnv + */ fun fromEnv(): BraintrustClient = builder().fromEnv().build() } - class Builder { + /** A builder for [BraintrustOkHttpClient]. */ + class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() - private var baseUrl: String = ClientOptions.PRODUCTION_URL - // default timeout for client is 1 minute - private var timeout: Duration = Duration.ofSeconds(60) private var proxy: Proxy? = null + private var sslSocketFactory: SSLSocketFactory? = null + private var trustManager: X509TrustManager? = null + private var hostnameVerifier: HostnameVerifier? = null - fun baseUrl(baseUrl: String) = apply { - clientOptions.baseUrl(baseUrl) - this.baseUrl = baseUrl + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + + /** + * 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 + } + + /** + * 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 + } + + /** + * 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 + } + + /** + * 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.braintrustdata.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: `https://api.braintrust.dev`. + */ + fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } + + /** + * 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) } + + fun headers(headers: Headers) = apply { clientOptions.headers(headers) } + fun headers(headers: Map>) = apply { clientOptions.headers(headers) } @@ -46,38 +189,99 @@ class BraintrustOkHttpClient private constructor() { clientOptions.putHeaders(name, values) } + fun putAllHeaders(headers: Headers) = apply { clientOptions.putAllHeaders(headers) } + fun putAllHeaders(headers: Map>) = apply { clientOptions.putAllHeaders(headers) } - fun removeHeader(name: String) = apply { clientOptions.removeHeader(name) } + fun replaceHeaders(name: String, value: String) = apply { + clientOptions.replaceHeaders(name, value) + } + + fun replaceHeaders(name: String, values: Iterable) = apply { + clientOptions.replaceHeaders(name, values) + } - fun timeout(timeout: Duration) = apply { this.timeout = timeout } + fun replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) } - fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + fun replaceAllHeaders(headers: Map>) = apply { + clientOptions.replaceAllHeaders(headers) + } - fun proxy(proxy: Proxy) = apply { this.proxy = proxy } + fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) } - fun responseValidation(responseValidation: Boolean) = apply { - clientOptions.responseValidation(responseValidation) + 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 apiKey(apiKey: String?) = apply { clientOptions.apiKey(apiKey) } + 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() } - fun build(): BraintrustClient { - return BraintrustClientImpl( + /** + * Returns an immutable instance of [BraintrustClient]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BraintrustClient = + BraintrustClientImpl( clientOptions .httpClient( OkHttpClient.builder() - .baseUrl(baseUrl) - .timeout(timeout) + .timeout(clientOptions.timeout()) .proxy(proxy) + .sslSocketFactory(sslSocketFactory) + .trustManager(trustManager) + .hostnameVerifier(hostnameVerifier) .build() ) .build() ) - } } } diff --git a/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.kt b/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.kt index 0b34647a..e5d7f18e 100755 --- a/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.kt +++ b/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/BraintrustOkHttpClientAsync.kt @@ -5,37 +5,180 @@ package com.braintrustdata.api.client.okhttp import com.braintrustdata.api.client.BraintrustClientAsync import com.braintrustdata.api.client.BraintrustClientAsyncImpl import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.core.Sleeper +import com.braintrustdata.api.core.Timeout +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.HttpClient +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.jsonMapper import com.fasterxml.jackson.databind.json.JsonMapper import java.net.Proxy import java.time.Clock import java.time.Duration +import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager +/** + * A class that allows building an instance of [BraintrustClientAsync] with [OkHttpClient] as the + * underlying [HttpClient]. + */ class BraintrustOkHttpClientAsync private constructor() { companion object { + /** Returns a mutable builder for constructing an instance of [BraintrustClientAsync]. */ fun builder() = Builder() + /** + * Returns a client configured using system properties and environment variables. + * + * @see ClientOptions.Builder.fromEnv + */ fun fromEnv(): BraintrustClientAsync = builder().fromEnv().build() } - class Builder { + /** A builder for [BraintrustOkHttpClientAsync]. */ + class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() - private var baseUrl: String = ClientOptions.PRODUCTION_URL - // default timeout for client is 1 minute - private var timeout: Duration = Duration.ofSeconds(60) private var proxy: Proxy? = null + private var sslSocketFactory: SSLSocketFactory? = null + private var trustManager: X509TrustManager? = null + private var hostnameVerifier: HostnameVerifier? = null - fun baseUrl(baseUrl: String) = apply { - clientOptions.baseUrl(baseUrl) - this.baseUrl = baseUrl + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + + /** + * 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 + } + + /** + * 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 + } + + /** + * 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 + } + + /** + * 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.braintrustdata.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: `https://api.braintrust.dev`. + */ + fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } + + /** + * 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) } + + fun headers(headers: Headers) = apply { clientOptions.headers(headers) } + fun headers(headers: Map>) = apply { clientOptions.headers(headers) } @@ -46,38 +189,99 @@ class BraintrustOkHttpClientAsync private constructor() { clientOptions.putHeaders(name, values) } + fun putAllHeaders(headers: Headers) = apply { clientOptions.putAllHeaders(headers) } + fun putAllHeaders(headers: Map>) = apply { clientOptions.putAllHeaders(headers) } - fun removeHeader(name: String) = apply { clientOptions.removeHeader(name) } + fun replaceHeaders(name: String, value: String) = apply { + clientOptions.replaceHeaders(name, value) + } + + fun replaceHeaders(name: String, values: Iterable) = apply { + clientOptions.replaceHeaders(name, values) + } - fun timeout(timeout: Duration) = apply { this.timeout = timeout } + fun replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) } - fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + fun replaceAllHeaders(headers: Map>) = apply { + clientOptions.replaceAllHeaders(headers) + } - fun proxy(proxy: Proxy) = apply { this.proxy = proxy } + fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) } - fun responseValidation(responseValidation: Boolean) = apply { - clientOptions.responseValidation(responseValidation) + 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 apiKey(apiKey: String?) = apply { clientOptions.apiKey(apiKey) } + 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() } - fun build(): BraintrustClientAsync { - return BraintrustClientAsyncImpl( + /** + * Returns an immutable instance of [BraintrustClientAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BraintrustClientAsync = + BraintrustClientAsyncImpl( clientOptions .httpClient( OkHttpClient.builder() - .baseUrl(baseUrl) - .timeout(timeout) + .timeout(clientOptions.timeout()) .proxy(proxy) + .sslSocketFactory(sslSocketFactory) + .trustManager(trustManager) + .hostnameVerifier(hostnameVerifier) .build() ) .build() ) - } } } diff --git a/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/OkHttpClient.kt b/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/OkHttpClient.kt index c1d1d5d4..000cf705 100755 --- a/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/OkHttpClient.kt +++ b/braintrust-kotlin-client-okhttp/src/main/kotlin/com/braintrustdata/api/client/okhttp/OkHttpClient.kt @@ -1,23 +1,24 @@ package com.braintrustdata.api.client.okhttp import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.Timeout +import com.braintrustdata.api.core.http.Headers import com.braintrustdata.api.core.http.HttpClient import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest import com.braintrustdata.api.core.http.HttpRequestBody import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.errors.BraintrustIoException -import com.google.common.collect.ListMultimap -import com.google.common.collect.MultimapBuilder import java.io.IOException import java.io.InputStream import java.net.Proxy import java.time.Duration +import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.Call import okhttp3.Callback -import okhttp3.Headers -import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType @@ -25,28 +26,14 @@ 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(private val okHttpClient: okhttp3.OkHttpClient, private val baseUrl: HttpUrl) : +class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpClient) : HttpClient { - private fun getClient(requestOptions: RequestOptions): okhttp3.OkHttpClient { - val timeout = requestOptions.timeout ?: return okHttpClient - return okHttpClient - .newBuilder() - .connectTimeout(timeout) - .readTimeout(timeout) - .writeTimeout(timeout) - .callTimeout(if (timeout.seconds == 0L) timeout else timeout.plusSeconds(30)) - .build() - } - - override fun execute( - request: HttpRequest, - requestOptions: RequestOptions, - ): HttpResponse { - val call = getClient(requestOptions).newCall(request.toRequest()) + override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { + val call = newCall(request, requestOptions) return try { call.execute().toResponse() @@ -61,7 +48,7 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val request: HttpRequest, requestOptions: RequestOptions, ): HttpResponse { - val call = getClient(requestOptions).newCall(request.toRequest()) + val call = newCall(request, requestOptions) return try { call.executeAsync().toResponse() @@ -78,27 +65,94 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val okHttpClient.cache?.close() } - private fun HttpRequest.toRequest(): Request { + private fun newCall(request: HttpRequest, requestOptions: RequestOptions): Call { + val clientBuilder = okHttpClient.newBuilder() + + val logLevel = + when (System.getenv("BRAINTRUST_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 suspend fun Call.executeAsync(): Response = + suspendCancellableCoroutine { continuation -> + continuation.invokeOnCancellation { this.cancel() } + + enqueue( + object : Callback { + override fun onFailure(call: Call, e: IOException) { + continuation.resumeWith(Result.failure(e)) + } + + override fun onResponse(call: Call, response: Response) { + continuation.resumeWith(Result.success(response)) + } + } + ) + } + + private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient): Request { var body: RequestBody? = body?.toRequestBody() - // OkHttpClient always requires a request body for PUT and POST methods - if (body == null && (method == HttpMethod.PUT || method == HttpMethod.POST)) { + if (body == null && requiresBody(method)) { body = "".toRequestBody() } val builder = Request.Builder().url(toUrl()).method(method.name, body) - headers.forEach(builder::header) + 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() } - private fun HttpRequest.toUrl(): String { - url?.let { - return it + /** `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 } - val builder = baseUrl.newBuilder() + private fun HttpRequest.toUrl(): String { + val builder = baseUrl.toHttpUrl().newBuilder() pathSegments.forEach(builder::addPathSegment) - queryParams.forEach(builder::addQueryParameter) + queryParams.keys().forEach { key -> + queryParams.values(key).forEach { builder.addQueryParameter(key, it) } + } return builder.toString() } @@ -108,21 +162,13 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val val length = contentLength() return object : RequestBody() { - override fun contentType(): MediaType? { - return mediaType - } + override fun contentType(): MediaType? = mediaType - override fun contentLength(): Long { - return length - } + override fun contentLength(): Long = length - override fun isOneShot(): Boolean { - return !repeatable() - } + override fun isOneShot(): Boolean = !repeatable() - override fun writeTo(sink: BufferedSink) { - writeTo(sink.outputStream()) - } + override fun writeTo(sink: BufferedSink) = writeTo(sink.outputStream()) } } @@ -130,80 +176,79 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val val headers = headers.toHeaders() return object : HttpResponse { - override fun statusCode(): Int { - return code - } + override fun statusCode(): Int = code - override fun headers(): ListMultimap { - return headers - } + override fun headers(): Headers = headers - override fun body(): InputStream { - return body!!.byteStream() - } + override fun body(): InputStream = body!!.byteStream() - override fun close() { - body!!.close() - } + override fun close() = body!!.close() } } - private fun Headers.toHeaders(): ListMultimap { - val headers = - MultimapBuilder.treeKeys(String.CASE_INSENSITIVE_ORDER) - .arrayListValues() - .build() - - forEach { pair -> headers.put(pair.first, pair.second) } - - return headers + private fun okhttp3.Headers.toHeaders(): Headers { + val headersBuilder = Headers.builder() + forEach { (name, value) -> headersBuilder.put(name, value) } + return headersBuilder.build() } companion object { fun builder() = Builder() } - class Builder { + class Builder internal constructor() { - private var baseUrl: HttpUrl? = null - // default timeout is 1 minute - private var timeout: Duration = Duration.ofSeconds(60) + 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 baseUrl(baseUrl: String) = apply { this.baseUrl = baseUrl.toHttpUrl() } + fun timeout(timeout: Timeout) = apply { this.timeout = timeout } - fun timeout(timeout: Duration) = apply { this.timeout = timeout } + fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build()) fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } - fun build(): OkHttpClient { - return OkHttpClient( - okhttp3.OkHttpClient.Builder() - .connectTimeout(timeout) - .readTimeout(timeout) - .writeTimeout(timeout) - .callTimeout(if (timeout.seconds == 0L) timeout else timeout.plusSeconds(30)) - .proxy(proxy) - .build(), - checkNotNull(baseUrl) { "`baseUrl` is required but was not set" }, - ) + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { + this.sslSocketFactory = sslSocketFactory } - } - private suspend fun Call.executeAsync(): Response = - suspendCancellableCoroutine { continuation -> - continuation.invokeOnCancellation { this.cancel() } + fun trustManager(trustManager: X509TrustManager?) = apply { + this.trustManager = trustManager + } - enqueue( - object : Callback { - override fun onFailure(call: Call, e: IOException) { - continuation.resumeWith(Result.failure(e)) - } + fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply { + this.hostnameVerifier = hostnameVerifier + } - override fun onResponse(call: Call, response: Response) { - continuation.resumeWith(Result.success(response)) + 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/braintrust-kotlin-core/build.gradle.kts b/braintrust-kotlin-core/build.gradle.kts index 52f11a1b..4bfcebba 100755 --- a/braintrust-kotlin-core/build.gradle.kts +++ b/braintrust-kotlin-core/build.gradle.kts @@ -3,15 +3,28 @@ plugins { id("braintrust.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.14.3") - api("com.fasterxml.jackson.core:jackson-databind:2.14.3") - api("com.google.guava:guava:33.0.0-jre") + 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.14.3") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.3") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.3") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.3") + 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") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") @@ -20,8 +33,10 @@ dependencies { testImplementation(project(":braintrust-kotlin-client-okhttp")) testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") testImplementation("org.assertj:assertj-core:3.25.3") - testImplementation("org.assertj:assertj-guava:3.25.3") - testImplementation("org.slf4j:slf4j-simple:2.0.12") 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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClient.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClient.kt index 3424863b..61ae99fb 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClient.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClient.kt @@ -1,16 +1,64 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.client -import com.braintrustdata.api.models.* -import com.braintrustdata.api.services.blocking.* - +import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.services.blocking.AclService +import com.braintrustdata.api.services.blocking.AiSecretService +import com.braintrustdata.api.services.blocking.ApiKeyService +import com.braintrustdata.api.services.blocking.DatasetService +import com.braintrustdata.api.services.blocking.EnvVarService +import com.braintrustdata.api.services.blocking.EvalService +import com.braintrustdata.api.services.blocking.ExperimentService +import com.braintrustdata.api.services.blocking.FunctionService +import com.braintrustdata.api.services.blocking.GroupService +import com.braintrustdata.api.services.blocking.OrganizationService +import com.braintrustdata.api.services.blocking.ProjectScoreService +import com.braintrustdata.api.services.blocking.ProjectService +import com.braintrustdata.api.services.blocking.ProjectTagService +import com.braintrustdata.api.services.blocking.PromptService +import com.braintrustdata.api.services.blocking.RoleService +import com.braintrustdata.api.services.blocking.SpanIframeService +import com.braintrustdata.api.services.blocking.TopLevelService +import com.braintrustdata.api.services.blocking.UserService +import com.braintrustdata.api.services.blocking.ViewService + +/** + * A client for interacting with the Braintrust 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 BraintrustClient { + /** + * 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(): BraintrustClientAsync + /** + * 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: (ClientOptions.Builder) -> Unit): BraintrustClient + fun topLevel(): TopLevelService fun projects(): ProjectService @@ -33,6 +81,8 @@ interface BraintrustClient { fun projectTags(): ProjectTagService + fun spanIframes(): SpanIframeService + fun functions(): FunctionService fun views(): ViewService @@ -46,4 +96,66 @@ interface BraintrustClient { fun envVars(): EnvVarService fun evals(): EvalService + + /** + * 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 [BraintrustClient] 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: (ClientOptions.Builder) -> Unit): BraintrustClient.WithRawResponse + + fun topLevel(): TopLevelService.WithRawResponse + + fun projects(): ProjectService.WithRawResponse + + fun experiments(): ExperimentService.WithRawResponse + + fun datasets(): DatasetService.WithRawResponse + + fun prompts(): PromptService.WithRawResponse + + fun roles(): RoleService.WithRawResponse + + fun groups(): GroupService.WithRawResponse + + fun acls(): AclService.WithRawResponse + + fun users(): UserService.WithRawResponse + + fun projectScores(): ProjectScoreService.WithRawResponse + + fun projectTags(): ProjectTagService.WithRawResponse + + fun spanIframes(): SpanIframeService.WithRawResponse + + fun functions(): FunctionService.WithRawResponse + + fun views(): ViewService.WithRawResponse + + fun organizations(): OrganizationService.WithRawResponse + + fun apiKeys(): ApiKeyService.WithRawResponse + + fun aiSecrets(): AiSecretService.WithRawResponse + + fun envVars(): EnvVarService.WithRawResponse + + fun evals(): EvalService.WithRawResponse + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsync.kt index 94511fd9..02e1825c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsync.kt @@ -1,16 +1,64 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.client -import com.braintrustdata.api.models.* -import com.braintrustdata.api.services.async.* - +import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.services.async.AclServiceAsync +import com.braintrustdata.api.services.async.AiSecretServiceAsync +import com.braintrustdata.api.services.async.ApiKeyServiceAsync +import com.braintrustdata.api.services.async.DatasetServiceAsync +import com.braintrustdata.api.services.async.EnvVarServiceAsync +import com.braintrustdata.api.services.async.EvalServiceAsync +import com.braintrustdata.api.services.async.ExperimentServiceAsync +import com.braintrustdata.api.services.async.FunctionServiceAsync +import com.braintrustdata.api.services.async.GroupServiceAsync +import com.braintrustdata.api.services.async.OrganizationServiceAsync +import com.braintrustdata.api.services.async.ProjectScoreServiceAsync +import com.braintrustdata.api.services.async.ProjectServiceAsync +import com.braintrustdata.api.services.async.ProjectTagServiceAsync +import com.braintrustdata.api.services.async.PromptServiceAsync +import com.braintrustdata.api.services.async.RoleServiceAsync +import com.braintrustdata.api.services.async.SpanIframeServiceAsync +import com.braintrustdata.api.services.async.TopLevelServiceAsync +import com.braintrustdata.api.services.async.UserServiceAsync +import com.braintrustdata.api.services.async.ViewServiceAsync + +/** + * A client for interacting with the Braintrust 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 BraintrustClientAsync { + /** + * 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(): BraintrustClient + /** + * 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: (ClientOptions.Builder) -> Unit): BraintrustClientAsync + fun topLevel(): TopLevelServiceAsync fun projects(): ProjectServiceAsync @@ -33,6 +81,8 @@ interface BraintrustClientAsync { fun projectTags(): ProjectTagServiceAsync + fun spanIframes(): SpanIframeServiceAsync + fun functions(): FunctionServiceAsync fun views(): ViewServiceAsync @@ -46,4 +96,70 @@ interface BraintrustClientAsync { fun envVars(): EnvVarServiceAsync fun evals(): EvalServiceAsync + + /** + * 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 [BraintrustClientAsync] 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: (ClientOptions.Builder) -> Unit + ): BraintrustClientAsync.WithRawResponse + + fun topLevel(): TopLevelServiceAsync.WithRawResponse + + fun projects(): ProjectServiceAsync.WithRawResponse + + fun experiments(): ExperimentServiceAsync.WithRawResponse + + fun datasets(): DatasetServiceAsync.WithRawResponse + + fun prompts(): PromptServiceAsync.WithRawResponse + + fun roles(): RoleServiceAsync.WithRawResponse + + fun groups(): GroupServiceAsync.WithRawResponse + + fun acls(): AclServiceAsync.WithRawResponse + + fun users(): UserServiceAsync.WithRawResponse + + fun projectScores(): ProjectScoreServiceAsync.WithRawResponse + + fun projectTags(): ProjectTagServiceAsync.WithRawResponse + + fun spanIframes(): SpanIframeServiceAsync.WithRawResponse + + fun functions(): FunctionServiceAsync.WithRawResponse + + fun views(): ViewServiceAsync.WithRawResponse + + fun organizations(): OrganizationServiceAsync.WithRawResponse + + fun apiKeys(): ApiKeyServiceAsync.WithRawResponse + + fun aiSecrets(): AiSecretServiceAsync.WithRawResponse + + fun envVars(): EnvVarServiceAsync.WithRawResponse + + fun evals(): EvalServiceAsync.WithRawResponse + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt index ee5f3110..d205ef41 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientAsyncImpl.kt @@ -3,67 +3,136 @@ package com.braintrustdata.api.client import com.braintrustdata.api.core.ClientOptions -import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError -import com.braintrustdata.api.models.* -import com.braintrustdata.api.services.async.* -import com.braintrustdata.api.services.errorHandler - -class BraintrustClientAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : BraintrustClientAsync { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - +import com.braintrustdata.api.core.getPackageVersion +import com.braintrustdata.api.services.async.AclServiceAsync +import com.braintrustdata.api.services.async.AclServiceAsyncImpl +import com.braintrustdata.api.services.async.AiSecretServiceAsync +import com.braintrustdata.api.services.async.AiSecretServiceAsyncImpl +import com.braintrustdata.api.services.async.ApiKeyServiceAsync +import com.braintrustdata.api.services.async.ApiKeyServiceAsyncImpl +import com.braintrustdata.api.services.async.DatasetServiceAsync +import com.braintrustdata.api.services.async.DatasetServiceAsyncImpl +import com.braintrustdata.api.services.async.EnvVarServiceAsync +import com.braintrustdata.api.services.async.EnvVarServiceAsyncImpl +import com.braintrustdata.api.services.async.EvalServiceAsync +import com.braintrustdata.api.services.async.EvalServiceAsyncImpl +import com.braintrustdata.api.services.async.ExperimentServiceAsync +import com.braintrustdata.api.services.async.ExperimentServiceAsyncImpl +import com.braintrustdata.api.services.async.FunctionServiceAsync +import com.braintrustdata.api.services.async.FunctionServiceAsyncImpl +import com.braintrustdata.api.services.async.GroupServiceAsync +import com.braintrustdata.api.services.async.GroupServiceAsyncImpl +import com.braintrustdata.api.services.async.OrganizationServiceAsync +import com.braintrustdata.api.services.async.OrganizationServiceAsyncImpl +import com.braintrustdata.api.services.async.ProjectScoreServiceAsync +import com.braintrustdata.api.services.async.ProjectScoreServiceAsyncImpl +import com.braintrustdata.api.services.async.ProjectServiceAsync +import com.braintrustdata.api.services.async.ProjectServiceAsyncImpl +import com.braintrustdata.api.services.async.ProjectTagServiceAsync +import com.braintrustdata.api.services.async.ProjectTagServiceAsyncImpl +import com.braintrustdata.api.services.async.PromptServiceAsync +import com.braintrustdata.api.services.async.PromptServiceAsyncImpl +import com.braintrustdata.api.services.async.RoleServiceAsync +import com.braintrustdata.api.services.async.RoleServiceAsyncImpl +import com.braintrustdata.api.services.async.SpanIframeServiceAsync +import com.braintrustdata.api.services.async.SpanIframeServiceAsyncImpl +import com.braintrustdata.api.services.async.TopLevelServiceAsync +import com.braintrustdata.api.services.async.TopLevelServiceAsyncImpl +import com.braintrustdata.api.services.async.UserServiceAsync +import com.braintrustdata.api.services.async.UserServiceAsyncImpl +import com.braintrustdata.api.services.async.ViewServiceAsync +import com.braintrustdata.api.services.async.ViewServiceAsyncImpl + +class BraintrustClientAsyncImpl(private val clientOptions: ClientOptions) : BraintrustClientAsync { + + private val clientOptionsWithUserAgent = + if (clientOptions.headers.names().contains("User-Agent")) clientOptions + else + clientOptions + .toBuilder() + .putHeader("User-Agent", "${javaClass.simpleName}/Kotlin ${getPackageVersion()}") + .build() + + // Pass the original clientOptions so that this client sets its own User-Agent. private val sync: BraintrustClient by lazy { BraintrustClientImpl(clientOptions) } - private val topLevel: TopLevelServiceAsync by lazy { TopLevelServiceAsyncImpl(clientOptions) } + private val withRawResponse: BraintrustClientAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val topLevel: TopLevelServiceAsync by lazy { + TopLevelServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val projects: ProjectServiceAsync by lazy { ProjectServiceAsyncImpl(clientOptions) } + private val projects: ProjectServiceAsync by lazy { + ProjectServiceAsyncImpl(clientOptionsWithUserAgent) + } private val experiments: ExperimentServiceAsync by lazy { - ExperimentServiceAsyncImpl(clientOptions) + ExperimentServiceAsyncImpl(clientOptionsWithUserAgent) } - private val datasets: DatasetServiceAsync by lazy { DatasetServiceAsyncImpl(clientOptions) } + private val datasets: DatasetServiceAsync by lazy { + DatasetServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val prompts: PromptServiceAsync by lazy { PromptServiceAsyncImpl(clientOptions) } + private val prompts: PromptServiceAsync by lazy { + PromptServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val roles: RoleServiceAsync by lazy { RoleServiceAsyncImpl(clientOptions) } + private val roles: RoleServiceAsync by lazy { RoleServiceAsyncImpl(clientOptionsWithUserAgent) } - private val groups: GroupServiceAsync by lazy { GroupServiceAsyncImpl(clientOptions) } + private val groups: GroupServiceAsync by lazy { + GroupServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val acls: AclServiceAsync by lazy { AclServiceAsyncImpl(clientOptions) } + private val acls: AclServiceAsync by lazy { AclServiceAsyncImpl(clientOptionsWithUserAgent) } - private val users: UserServiceAsync by lazy { UserServiceAsyncImpl(clientOptions) } + private val users: UserServiceAsync by lazy { UserServiceAsyncImpl(clientOptionsWithUserAgent) } private val projectScores: ProjectScoreServiceAsync by lazy { - ProjectScoreServiceAsyncImpl(clientOptions) + ProjectScoreServiceAsyncImpl(clientOptionsWithUserAgent) } private val projectTags: ProjectTagServiceAsync by lazy { - ProjectTagServiceAsyncImpl(clientOptions) + ProjectTagServiceAsyncImpl(clientOptionsWithUserAgent) + } + + private val spanIframes: SpanIframeServiceAsync by lazy { + SpanIframeServiceAsyncImpl(clientOptionsWithUserAgent) } - private val functions: FunctionServiceAsync by lazy { FunctionServiceAsyncImpl(clientOptions) } + private val functions: FunctionServiceAsync by lazy { + FunctionServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val views: ViewServiceAsync by lazy { ViewServiceAsyncImpl(clientOptions) } + private val views: ViewServiceAsync by lazy { ViewServiceAsyncImpl(clientOptionsWithUserAgent) } private val organizations: OrganizationServiceAsync by lazy { - OrganizationServiceAsyncImpl(clientOptions) + OrganizationServiceAsyncImpl(clientOptionsWithUserAgent) } - private val apiKeys: ApiKeyServiceAsync by lazy { ApiKeyServiceAsyncImpl(clientOptions) } + private val apiKeys: ApiKeyServiceAsync by lazy { + ApiKeyServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val aiSecrets: AiSecretServiceAsync by lazy { AiSecretServiceAsyncImpl(clientOptions) } + private val aiSecrets: AiSecretServiceAsync by lazy { + AiSecretServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val envVars: EnvVarServiceAsync by lazy { EnvVarServiceAsyncImpl(clientOptions) } + private val envVars: EnvVarServiceAsync by lazy { + EnvVarServiceAsyncImpl(clientOptionsWithUserAgent) + } - private val evals: EvalServiceAsync by lazy { EvalServiceAsyncImpl(clientOptions) } + private val evals: EvalServiceAsync by lazy { EvalServiceAsyncImpl(clientOptionsWithUserAgent) } override fun sync(): BraintrustClient = sync + override fun withRawResponse(): BraintrustClientAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): BraintrustClientAsync = + BraintrustClientAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + override fun topLevel(): TopLevelServiceAsync = topLevel override fun projects(): ProjectServiceAsync = projects @@ -86,6 +155,8 @@ constructor( override fun projectTags(): ProjectTagServiceAsync = projectTags + override fun spanIframes(): SpanIframeServiceAsync = spanIframes + override fun functions(): FunctionServiceAsync = functions override fun views(): ViewServiceAsync = views @@ -99,4 +170,131 @@ constructor( override fun envVars(): EnvVarServiceAsync = envVars override fun evals(): EvalServiceAsync = evals + + override fun close() = clientOptions.close() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + BraintrustClientAsync.WithRawResponse { + + private val topLevel: TopLevelServiceAsync.WithRawResponse by lazy { + TopLevelServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val projects: ProjectServiceAsync.WithRawResponse by lazy { + ProjectServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val experiments: ExperimentServiceAsync.WithRawResponse by lazy { + ExperimentServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val datasets: DatasetServiceAsync.WithRawResponse by lazy { + DatasetServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val prompts: PromptServiceAsync.WithRawResponse by lazy { + PromptServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val roles: RoleServiceAsync.WithRawResponse by lazy { + RoleServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val groups: GroupServiceAsync.WithRawResponse by lazy { + GroupServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val acls: AclServiceAsync.WithRawResponse by lazy { + AclServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val users: UserServiceAsync.WithRawResponse by lazy { + UserServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val projectScores: ProjectScoreServiceAsync.WithRawResponse by lazy { + ProjectScoreServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val projectTags: ProjectTagServiceAsync.WithRawResponse by lazy { + ProjectTagServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val spanIframes: SpanIframeServiceAsync.WithRawResponse by lazy { + SpanIframeServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val functions: FunctionServiceAsync.WithRawResponse by lazy { + FunctionServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val views: ViewServiceAsync.WithRawResponse by lazy { + ViewServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val organizations: OrganizationServiceAsync.WithRawResponse by lazy { + OrganizationServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val apiKeys: ApiKeyServiceAsync.WithRawResponse by lazy { + ApiKeyServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val aiSecrets: AiSecretServiceAsync.WithRawResponse by lazy { + AiSecretServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val envVars: EnvVarServiceAsync.WithRawResponse by lazy { + EnvVarServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + private val evals: EvalServiceAsync.WithRawResponse by lazy { + EvalServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): BraintrustClientAsync.WithRawResponse = + BraintrustClientAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + override fun topLevel(): TopLevelServiceAsync.WithRawResponse = topLevel + + override fun projects(): ProjectServiceAsync.WithRawResponse = projects + + override fun experiments(): ExperimentServiceAsync.WithRawResponse = experiments + + override fun datasets(): DatasetServiceAsync.WithRawResponse = datasets + + override fun prompts(): PromptServiceAsync.WithRawResponse = prompts + + override fun roles(): RoleServiceAsync.WithRawResponse = roles + + override fun groups(): GroupServiceAsync.WithRawResponse = groups + + override fun acls(): AclServiceAsync.WithRawResponse = acls + + override fun users(): UserServiceAsync.WithRawResponse = users + + override fun projectScores(): ProjectScoreServiceAsync.WithRawResponse = projectScores + + override fun projectTags(): ProjectTagServiceAsync.WithRawResponse = projectTags + + override fun spanIframes(): SpanIframeServiceAsync.WithRawResponse = spanIframes + + override fun functions(): FunctionServiceAsync.WithRawResponse = functions + + override fun views(): ViewServiceAsync.WithRawResponse = views + + override fun organizations(): OrganizationServiceAsync.WithRawResponse = organizations + + override fun apiKeys(): ApiKeyServiceAsync.WithRawResponse = apiKeys + + override fun aiSecrets(): AiSecretServiceAsync.WithRawResponse = aiSecrets + + override fun envVars(): EnvVarServiceAsync.WithRawResponse = envVars + + override fun evals(): EvalServiceAsync.WithRawResponse = evals + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt index e23daeb0..e1e73b9b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/client/BraintrustClientImpl.kt @@ -3,63 +3,124 @@ package com.braintrustdata.api.client import com.braintrustdata.api.core.ClientOptions -import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError -import com.braintrustdata.api.models.* -import com.braintrustdata.api.services.blocking.* -import com.braintrustdata.api.services.errorHandler - -class BraintrustClientImpl -constructor( - private val clientOptions: ClientOptions, -) : BraintrustClient { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - +import com.braintrustdata.api.core.getPackageVersion +import com.braintrustdata.api.services.blocking.AclService +import com.braintrustdata.api.services.blocking.AclServiceImpl +import com.braintrustdata.api.services.blocking.AiSecretService +import com.braintrustdata.api.services.blocking.AiSecretServiceImpl +import com.braintrustdata.api.services.blocking.ApiKeyService +import com.braintrustdata.api.services.blocking.ApiKeyServiceImpl +import com.braintrustdata.api.services.blocking.DatasetService +import com.braintrustdata.api.services.blocking.DatasetServiceImpl +import com.braintrustdata.api.services.blocking.EnvVarService +import com.braintrustdata.api.services.blocking.EnvVarServiceImpl +import com.braintrustdata.api.services.blocking.EvalService +import com.braintrustdata.api.services.blocking.EvalServiceImpl +import com.braintrustdata.api.services.blocking.ExperimentService +import com.braintrustdata.api.services.blocking.ExperimentServiceImpl +import com.braintrustdata.api.services.blocking.FunctionService +import com.braintrustdata.api.services.blocking.FunctionServiceImpl +import com.braintrustdata.api.services.blocking.GroupService +import com.braintrustdata.api.services.blocking.GroupServiceImpl +import com.braintrustdata.api.services.blocking.OrganizationService +import com.braintrustdata.api.services.blocking.OrganizationServiceImpl +import com.braintrustdata.api.services.blocking.ProjectScoreService +import com.braintrustdata.api.services.blocking.ProjectScoreServiceImpl +import com.braintrustdata.api.services.blocking.ProjectService +import com.braintrustdata.api.services.blocking.ProjectServiceImpl +import com.braintrustdata.api.services.blocking.ProjectTagService +import com.braintrustdata.api.services.blocking.ProjectTagServiceImpl +import com.braintrustdata.api.services.blocking.PromptService +import com.braintrustdata.api.services.blocking.PromptServiceImpl +import com.braintrustdata.api.services.blocking.RoleService +import com.braintrustdata.api.services.blocking.RoleServiceImpl +import com.braintrustdata.api.services.blocking.SpanIframeService +import com.braintrustdata.api.services.blocking.SpanIframeServiceImpl +import com.braintrustdata.api.services.blocking.TopLevelService +import com.braintrustdata.api.services.blocking.TopLevelServiceImpl +import com.braintrustdata.api.services.blocking.UserService +import com.braintrustdata.api.services.blocking.UserServiceImpl +import com.braintrustdata.api.services.blocking.ViewService +import com.braintrustdata.api.services.blocking.ViewServiceImpl + +class BraintrustClientImpl(private val clientOptions: ClientOptions) : BraintrustClient { + + private val clientOptionsWithUserAgent = + if (clientOptions.headers.names().contains("User-Agent")) clientOptions + else + clientOptions + .toBuilder() + .putHeader("User-Agent", "${javaClass.simpleName}/Kotlin ${getPackageVersion()}") + .build() + + // Pass the original clientOptions so that this client sets its own User-Agent. private val async: BraintrustClientAsync by lazy { BraintrustClientAsyncImpl(clientOptions) } - private val topLevel: TopLevelService by lazy { TopLevelServiceImpl(clientOptions) } + private val withRawResponse: BraintrustClient.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val topLevel: TopLevelService by lazy { + TopLevelServiceImpl(clientOptionsWithUserAgent) + } - private val projects: ProjectService by lazy { ProjectServiceImpl(clientOptions) } + private val projects: ProjectService by lazy { ProjectServiceImpl(clientOptionsWithUserAgent) } - private val experiments: ExperimentService by lazy { ExperimentServiceImpl(clientOptions) } + private val experiments: ExperimentService by lazy { + ExperimentServiceImpl(clientOptionsWithUserAgent) + } - private val datasets: DatasetService by lazy { DatasetServiceImpl(clientOptions) } + private val datasets: DatasetService by lazy { DatasetServiceImpl(clientOptionsWithUserAgent) } - private val prompts: PromptService by lazy { PromptServiceImpl(clientOptions) } + private val prompts: PromptService by lazy { PromptServiceImpl(clientOptionsWithUserAgent) } - private val roles: RoleService by lazy { RoleServiceImpl(clientOptions) } + private val roles: RoleService by lazy { RoleServiceImpl(clientOptionsWithUserAgent) } - private val groups: GroupService by lazy { GroupServiceImpl(clientOptions) } + private val groups: GroupService by lazy { GroupServiceImpl(clientOptionsWithUserAgent) } - private val acls: AclService by lazy { AclServiceImpl(clientOptions) } + private val acls: AclService by lazy { AclServiceImpl(clientOptionsWithUserAgent) } - private val users: UserService by lazy { UserServiceImpl(clientOptions) } + private val users: UserService by lazy { UserServiceImpl(clientOptionsWithUserAgent) } private val projectScores: ProjectScoreService by lazy { - ProjectScoreServiceImpl(clientOptions) + ProjectScoreServiceImpl(clientOptionsWithUserAgent) } - private val projectTags: ProjectTagService by lazy { ProjectTagServiceImpl(clientOptions) } + private val projectTags: ProjectTagService by lazy { + ProjectTagServiceImpl(clientOptionsWithUserAgent) + } - private val functions: FunctionService by lazy { FunctionServiceImpl(clientOptions) } + private val spanIframes: SpanIframeService by lazy { + SpanIframeServiceImpl(clientOptionsWithUserAgent) + } + + private val functions: FunctionService by lazy { + FunctionServiceImpl(clientOptionsWithUserAgent) + } - private val views: ViewService by lazy { ViewServiceImpl(clientOptions) } + private val views: ViewService by lazy { ViewServiceImpl(clientOptionsWithUserAgent) } private val organizations: OrganizationService by lazy { - OrganizationServiceImpl(clientOptions) + OrganizationServiceImpl(clientOptionsWithUserAgent) } - private val apiKeys: ApiKeyService by lazy { ApiKeyServiceImpl(clientOptions) } + private val apiKeys: ApiKeyService by lazy { ApiKeyServiceImpl(clientOptionsWithUserAgent) } - private val aiSecrets: AiSecretService by lazy { AiSecretServiceImpl(clientOptions) } + private val aiSecrets: AiSecretService by lazy { + AiSecretServiceImpl(clientOptionsWithUserAgent) + } - private val envVars: EnvVarService by lazy { EnvVarServiceImpl(clientOptions) } + private val envVars: EnvVarService by lazy { EnvVarServiceImpl(clientOptionsWithUserAgent) } - private val evals: EvalService by lazy { EvalServiceImpl(clientOptions) } + private val evals: EvalService by lazy { EvalServiceImpl(clientOptionsWithUserAgent) } override fun async(): BraintrustClientAsync = async + override fun withRawResponse(): BraintrustClient.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): BraintrustClient = + BraintrustClientImpl(clientOptions.toBuilder().apply(modifier).build()) + override fun topLevel(): TopLevelService = topLevel override fun projects(): ProjectService = projects @@ -82,6 +143,8 @@ constructor( override fun projectTags(): ProjectTagService = projectTags + override fun spanIframes(): SpanIframeService = spanIframes + override fun functions(): FunctionService = functions override fun views(): ViewService = views @@ -95,4 +158,131 @@ constructor( override fun envVars(): EnvVarService = envVars override fun evals(): EvalService = evals + + override fun close() = clientOptions.close() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + BraintrustClient.WithRawResponse { + + private val topLevel: TopLevelService.WithRawResponse by lazy { + TopLevelServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val projects: ProjectService.WithRawResponse by lazy { + ProjectServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val experiments: ExperimentService.WithRawResponse by lazy { + ExperimentServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val datasets: DatasetService.WithRawResponse by lazy { + DatasetServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val prompts: PromptService.WithRawResponse by lazy { + PromptServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val roles: RoleService.WithRawResponse by lazy { + RoleServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val groups: GroupService.WithRawResponse by lazy { + GroupServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val acls: AclService.WithRawResponse by lazy { + AclServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val users: UserService.WithRawResponse by lazy { + UserServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val projectScores: ProjectScoreService.WithRawResponse by lazy { + ProjectScoreServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val projectTags: ProjectTagService.WithRawResponse by lazy { + ProjectTagServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val spanIframes: SpanIframeService.WithRawResponse by lazy { + SpanIframeServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val functions: FunctionService.WithRawResponse by lazy { + FunctionServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val views: ViewService.WithRawResponse by lazy { + ViewServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val organizations: OrganizationService.WithRawResponse by lazy { + OrganizationServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val apiKeys: ApiKeyService.WithRawResponse by lazy { + ApiKeyServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val aiSecrets: AiSecretService.WithRawResponse by lazy { + AiSecretServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val envVars: EnvVarService.WithRawResponse by lazy { + EnvVarServiceImpl.WithRawResponseImpl(clientOptions) + } + + private val evals: EvalService.WithRawResponse by lazy { + EvalServiceImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): BraintrustClient.WithRawResponse = + BraintrustClientImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + override fun topLevel(): TopLevelService.WithRawResponse = topLevel + + override fun projects(): ProjectService.WithRawResponse = projects + + override fun experiments(): ExperimentService.WithRawResponse = experiments + + override fun datasets(): DatasetService.WithRawResponse = datasets + + override fun prompts(): PromptService.WithRawResponse = prompts + + override fun roles(): RoleService.WithRawResponse = roles + + override fun groups(): GroupService.WithRawResponse = groups + + override fun acls(): AclService.WithRawResponse = acls + + override fun users(): UserService.WithRawResponse = users + + override fun projectScores(): ProjectScoreService.WithRawResponse = projectScores + + override fun projectTags(): ProjectTagService.WithRawResponse = projectTags + + override fun spanIframes(): SpanIframeService.WithRawResponse = spanIframes + + override fun functions(): FunctionService.WithRawResponse = functions + + override fun views(): ViewService.WithRawResponse = views + + override fun organizations(): OrganizationService.WithRawResponse = organizations + + override fun apiKeys(): ApiKeyService.WithRawResponse = apiKeys + + override fun aiSecrets(): AiSecretService.WithRawResponse = aiSecrets + + override fun envVars(): EnvVarService.WithRawResponse = envVars + + override fun evals(): EvalService.WithRawResponse = evals + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/AutoPager.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/AutoPager.kt new file mode 100644 index 00000000..015c2bc7 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/AutoPager.kt @@ -0,0 +1,16 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +class AutoPager private constructor(private val firstPage: Page) : Sequence { + + companion object { + + fun from(firstPage: Page): AutoPager = AutoPager(firstPage) + } + + override fun iterator(): Iterator = + generateSequence(firstPage) { if (it.hasNextPage()) it.nextPage() else null } + .flatMap { it.items() } + .iterator() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/AutoPagerAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/AutoPagerAsync.kt new file mode 100644 index 00000000..a9aa86f7 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/AutoPagerAsync.kt @@ -0,0 +1,27 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.emitAll + +class AutoPagerAsync private constructor(private val firstPage: PageAsync) : Flow { + + companion object { + + fun from(firstPage: PageAsync): AutoPagerAsync = AutoPagerAsync(firstPage) + } + + override suspend fun collect(collector: FlowCollector) { + var page: PageAsync = firstPage + while (true) { + collector.emitAll(page.items().asFlow()) + if (!page.hasNextPage()) { + break + } + page = page.nextPage() + } + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/BaseDeserializer.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/BaseDeserializer.kt index a38e39bd..3ebb507f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/BaseDeserializer.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/BaseDeserializer.kt @@ -7,7 +7,6 @@ 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.JsonMappingException import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.deser.ContextualDeserializer import com.fasterxml.jackson.databind.deser.std.StdDeserializer @@ -18,7 +17,7 @@ abstract class BaseDeserializer(type: KClass) : override fun createContextual( context: DeserializationContext, - property: BeanProperty? + property: BeanProperty?, ): JsonDeserializer { return this } @@ -29,31 +28,17 @@ abstract class BaseDeserializer(type: KClass) : protected abstract fun ObjectCodec.deserialize(node: JsonNode): T - protected fun ObjectCodec.tryDeserialize( - node: JsonNode, - type: TypeReference, - validate: (T) -> Unit = {} - ): T? { - return try { - readValue(treeAsTokens(node), type).apply(validate) - } catch (e: JsonMappingException) { - null - } catch (e: RuntimeException) { + 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, - validate: (T) -> Unit = {} - ): T? { - return try { - readValue(treeAsTokens(node), type).apply(validate) - } catch (e: JsonMappingException) { - null - } catch (e: RuntimeException) { + protected fun ObjectCodec.tryDeserialize(node: JsonNode, type: JavaType): T? = + try { + readValue(treeAsTokens(node), type) + } catch (e: Exception) { null } - } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Check.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Check.kt new file mode 100644 index 00000000..213a7182 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Check.kt @@ -0,0 +1,86 @@ +package com.braintrustdata.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" } + +internal fun checkKnown(name: String, value: JsonField): T = + value.asKnown() + ?: throw IllegalStateException("`$name` is not a known type: ${value.javaClass.simpleName}") + +internal fun checkKnown(name: String, value: MultipartField): T = + value.value.asKnown() + ?: throw IllegalStateException("`$name` is not a known type: ${value.javaClass.simpleName}") + +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}" } + } + +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}" + } + } + +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}" + } + } + +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/braintrustdata/braintrust-kotlin#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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ClientOptions.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ClientOptions.kt index 2208167f..11b9be6b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ClientOptions.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ClientOptions.kt @@ -2,133 +2,439 @@ package com.braintrustdata.api.core +import com.braintrustdata.api.core.http.Headers import com.braintrustdata.api.core.http.HttpClient +import com.braintrustdata.api.core.http.PhantomReachableClosingHttpClient +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.core.http.RetryingHttpClient import com.fasterxml.jackson.databind.json.JsonMapper -import com.google.common.collect.ArrayListMultimap -import com.google.common.collect.ListMultimap import java.time.Clock +import java.time.Duration +/** 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 `braintrust-kotlin-client-okhttp` or implement your own. + * + * This class takes ownership of the client and closes it when closed. + */ 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. + */ + val checkJacksonVersionCompatibility: Boolean, + /** + * The Jackson JSON mapper to use for serializing and deserializing JSON. + * + * Defaults to [com.braintrustdata.api.core.jsonMapper]. The default is usually sufficient and + * rarely needs to be overridden. + */ 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. + */ + 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]. + */ val clock: Clock, - val baseUrl: String, - val apiKey: String?, - val headers: ListMultimap, - val queryParams: ListMultimap, + private val baseUrl: String?, + /** Headers to send with the request. */ + val headers: Headers, + /** Query params to send with the request. */ + 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. + */ val responseValidation: Boolean, + /** + * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding + * retries. + * + * Defaults to [Timeout.default]. + */ + 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. + */ + val maxRetries: Int, + val apiKey: String?, ) { + init { + if (checkJacksonVersionCompatibility) { + checkJacksonVersionCompatibility() + } + } + + /** + * The base URL to use for every request. + * + * Defaults to the production environment: `https://api.braintrust.dev`. + */ + fun baseUrl(): String = baseUrl ?: PRODUCTION_URL + + fun toBuilder() = Builder().from(this) + companion object { const val PRODUCTION_URL = "https://api.braintrust.dev" + /** + * Returns a mutable builder for constructing an instance of [ClientOptions]. + * + * The following fields are required: + * ```kotlin + * .httpClient() + * ``` + */ fun builder() = Builder() + /** + * Returns options configured using system properties and environment variables. + * + * @see Builder.fromEnv + */ fun fromEnv(): ClientOptions = builder().fromEnv().build() } - class Builder { + /** A builder for [ClientOptions]. */ + class Builder internal constructor() { private var httpClient: HttpClient? = null - private var jsonMapper: JsonMapper? = 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 = PRODUCTION_URL - private var headers: MutableMap> = mutableMapOf() - private var queryParams: MutableMap> = mutableMapOf() + 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 - fun httpClient(httpClient: HttpClient) = apply { this.httpClient = httpClient } + 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 `braintrust-kotlin-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.braintrustdata.api.core.jsonMapper]. The default is usually sufficient + * and rarely needs to be overridden. + */ fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper } - fun baseUrl(baseUrl: String) = apply { this.baseUrl = baseUrl } + /** + * 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: `https://api.braintrust.dev`. + */ + fun baseUrl(baseUrl: String?) = apply { this.baseUrl = baseUrl } + + /** + * 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 } + + 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 { - this.headers.getOrPut(name) { mutableListOf() }.add(value) + 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 putHeaders(name: String, values: Iterable) = apply { - this.headers.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceHeaders(name: String, value: String) = apply { headers.replace(name, value) } + + fun replaceHeaders(name: String, values: Iterable) = apply { + headers.replace(name, values) } - fun putAllHeaders(headers: Map>) = apply { - headers.forEach(this::putHeaders) + fun replaceAllHeaders(headers: Headers) = apply { this.headers.replaceAll(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + this.headers.replaceAll(headers) } - fun removeHeader(name: String) = apply { this.headers.put(name, mutableListOf()) } + 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(name: String, value: String) = apply { - this.queryParams.getOrPut(name) { mutableListOf() }.add(value) + fun putQueryParam(key: String, value: String) = apply { queryParams.put(key, value) } + + fun putQueryParams(key: String, values: Iterable) = apply { + queryParams.put(key, values) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.queryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAllQueryParams(queryParams: QueryParams) = apply { + this.queryParams.putAll(queryParams) } fun putAllQueryParams(queryParams: Map>) = apply { - queryParams.forEach(this::putQueryParams) + this.queryParams.putAll(queryParams) } - fun removeQueryParam(name: String) = apply { this.queryParams.put(name, mutableListOf()) } + fun replaceQueryParams(key: String, value: String) = apply { + queryParams.replace(key, value) + } - fun responseValidation(responseValidation: Boolean) = apply { - this.responseValidation = responseValidation + fun replaceQueryParams(key: String, values: Iterable) = apply { + queryParams.replace(key, values) } - fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } + fun replaceAllQueryParams(queryParams: QueryParams) = apply { + this.queryParams.replaceAll(queryParams) + } - fun apiKey(apiKey: String?) = apply { this.apiKey = apiKey } + 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 fromEnv() = apply { System.getenv("BRAINTRUST_API_KEY")?.let { apiKey(it) } } + 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` |`braintrust.apiKey` |`BRAINTRUST_API_KEY` |false |- | + * |`baseUrl`|`braintrust.baseUrl`|`BRAINTRUST_BASE_URL`|true |`"https://api.braintrust.dev"`| + * + * System properties take precedence over environment variables. + */ + fun fromEnv() = apply { + (System.getProperty("braintrust.baseUrl") ?: System.getenv("BRAINTRUST_BASE_URL")) + ?.let { baseUrl(it) } + (System.getProperty("braintrust.apiKey") ?: System.getenv("BRAINTRUST_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: + * ```kotlin + * .httpClient() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ClientOptions { - checkNotNull(httpClient) { "`httpClient` is required but was not set" } + val httpClient = checkRequired("httpClient", httpClient) + val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) - val headers = ArrayListMultimap.create() - val queryParams = ArrayListMultimap.create() + val headers = Headers.builder() + val queryParams = QueryParams.builder() headers.put("X-Stainless-Lang", "kotlin") 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()) - if (!apiKey.isNullOrEmpty()) { - headers.put("Authorization", "Bearer ${apiKey}") + apiKey?.let { + if (!it.isEmpty()) { + headers.put("Authorization", "Bearer $it") + } } - this.headers.forEach(headers::replaceValues) - this.queryParams.forEach(queryParams::replaceValues) + headers.replaceAll(this.headers.build()) + queryParams.replaceAll(this.queryParams.build()) return ClientOptions( + httpClient, RetryingHttpClient.builder() - .httpClient(httpClient!!) + .httpClient(httpClient) + .sleeper(sleeper) .clock(clock) .maxRetries(maxRetries) .build(), - jsonMapper ?: jsonMapper(), + checkJacksonVersionCompatibility, + jsonMapper, + sleeper, clock, baseUrl, - apiKey, - headers.toUnmodifiable(), - queryParams.toUnmodifiable(), + 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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/DefaultSleeper.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/DefaultSleeper.kt new file mode 100644 index 00000000..5ca9b87d --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/DefaultSleeper.kt @@ -0,0 +1,14 @@ +package com.braintrustdata.api.core + +import java.time.Duration +import kotlin.time.toKotlinDuration +import kotlinx.coroutines.delay + +class DefaultSleeper : Sleeper { + + override fun sleep(duration: Duration) = Thread.sleep(duration.toMillis()) + + override suspend fun sleepAsync(duration: Duration) = delay(duration.toKotlinDuration()) + + override fun close() {} +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ObjectMappers.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ObjectMappers.kt index 5b1f8ea1..c3287a6b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ObjectMappers.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/ObjectMappers.kt @@ -3,23 +3,165 @@ package com.braintrustdata.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.cfg.CoercionAction.Fail -import com.fasterxml.jackson.databind.cfg.CoercionInputShape.Integer +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.jacksonMapperBuilder +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 = - jacksonMapperBuilder() + 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) - .withCoercionConfig(String::class.java) { it.setCoercion(Integer, Fail) } + .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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Page.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Page.kt new file mode 100644 index 00000000..5d5afd20 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Page.kt @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +/** + * An interface representing a single page, with items of type [T], from a paginated endpoint + * response. + * + * Implementations of this interface are expected to request additional pages synchronously. For + * asynchronous pagination, see the [PageAsync] interface. + */ +interface Page { + + /** + * Returns whether there's another page after this one. + * + * The method generally doesn't make requests so the result depends entirely on the data in this + * page. If a significant amount of time has passed between requesting this page and calling + * this method, then the result could be stale. + */ + fun hasNextPage(): Boolean + + /** + * Returns the page after this one by making another request. + * + * @throws IllegalStateException if it's impossible to get the next page. This exception is + * avoidable by calling [hasNextPage] first. + */ + fun nextPage(): Page + + /** Returns the items in this page. */ + fun items(): List +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PageAsync.kt new file mode 100644 index 00000000..69c49958 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PageAsync.kt @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +/** + * An interface representing a single page, with items of type [T], from a paginated endpoint + * response. + * + * Implementations of this interface are expected to request additional pages asynchronously. For + * synchronous pagination, see the [Page] interface. + */ +interface PageAsync { + + /** + * Returns whether there's another page after this one. + * + * The method generally doesn't make requests so the result depends entirely on the data in this + * page. If a significant amount of time has passed between requesting this page and calling + * this method, then the result could be stale. + */ + fun hasNextPage(): Boolean + + /** + * Returns the page after this one by making another request. + * + * @throws IllegalStateException if it's impossible to get the next page. This exception is + * avoidable by calling [hasNextPage] first. + */ + suspend fun nextPage(): PageAsync + + /** Returns the items in this page. */ + fun items(): List +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Params.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Params.kt new file mode 100644 index 00000000..f98bf142 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Params.kt @@ -0,0 +1,16 @@ +package com.braintrustdata.api.core + +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachable.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachable.kt new file mode 100644 index 00000000..d45baed6 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachable.kt @@ -0,0 +1,54 @@ +@file:JvmName("PhantomReachable") + +package com.braintrustdata.api.core + +import com.braintrustdata.api.errors.BraintrustException +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. + */ +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. + */ +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 BraintrustException("Unexpected reflective invocation failure", e) + } + } + } catch (e: ReflectiveOperationException) { + // We're running Java 8, which has no Cleaner. + null + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachableExecutorService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachableExecutorService.kt new file mode 100644 index 00000000..0538d523 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachableExecutorService.kt @@ -0,0 +1,58 @@ +package com.braintrustdata.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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachableSleeper.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachableSleeper.kt new file mode 100644 index 00000000..eabb2859 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PhantomReachableSleeper.kt @@ -0,0 +1,21 @@ +package com.braintrustdata.api.core + +import java.time.Duration + +/** + * 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 suspend fun sleepAsync(duration: Duration) = sleeper.sleepAsync(duration) + + override fun close() = sleeper.close() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PrepareRequest.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PrepareRequest.kt new file mode 100644 index 00000000..32c58546 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/PrepareRequest.kt @@ -0,0 +1,16 @@ +package com.braintrustdata.api.core + +import com.braintrustdata.api.core.http.HttpRequest + +internal fun HttpRequest.prepare(clientOptions: ClientOptions, params: Params): HttpRequest = + toBuilder() + .putAllQueryParams(clientOptions.queryParams) + .replaceAllQueryParams(params._queryParams()) + .putAllHeaders(clientOptions.headers) + .replaceAllHeaders(params._headers()) + .build() + +internal suspend fun HttpRequest.prepareAsync(clientOptions: ClientOptions, params: Params) = + // This async version exists to make it easier to add async specific preparation logic in the + // future. + prepare(clientOptions, params) diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Properties.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Properties.kt index 1c59eee1..5130de1b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Properties.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Properties.kt @@ -2,7 +2,7 @@ package com.braintrustdata.api.core -import java.util.Properties +import com.braintrustdata.api.client.BraintrustClient fun getOsArch(): String { val osArch = System.getProperty("os.arch") @@ -16,7 +16,7 @@ fun getOsArch(): String { "x86_64" -> "x64" "arm" -> "arm" "aarch64" -> "arm64" - else -> "other:${osArch}" + else -> "other:$osArch" } } @@ -30,18 +30,13 @@ fun getOsName(): String { osName.startsWith("Linux") -> "Linux" osName.startsWith("Mac OS") -> "MacOS" osName.startsWith("Windows") -> "Windows" - else -> "Other:${osName}" + else -> "Other:$osName" } } -fun getOsVersion(): String { - return System.getProperty("os.version", "unknown") -} +fun getOsVersion(): String = System.getProperty("os.version", "unknown") -fun getPackageVersion(): String { - return Properties::class.java.`package`.implementationVersion ?: "unknown" -} +fun getPackageVersion(): String = + BraintrustClient::class.java.`package`.implementationVersion ?: "unknown" -fun getJavaVersion(): String { - return System.getProperty("java.version", "unknown") -} +fun getJavaVersion(): String = System.getProperty("java.version", "unknown") diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/RequestOptions.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/RequestOptions.kt index b03a0cf0..a1abbc5e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/RequestOptions.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/RequestOptions.kt @@ -2,17 +2,7 @@ package com.braintrustdata.api.core import java.time.Duration -class RequestOptions -private constructor( - val responseValidation: Boolean?, - val timeout: Duration?, -) { - fun applyDefaults(options: RequestOptions): RequestOptions { - return RequestOptions( - responseValidation = this.responseValidation ?: options.responseValidation, - timeout = this.timeout ?: options.timeout - ) - } +class RequestOptions private constructor(val responseValidation: Boolean?, val timeout: Timeout?) { companion object { @@ -20,21 +10,36 @@ private constructor( fun none() = NONE + internal fun from(clientOptions: ClientOptions): RequestOptions = + builder() + .responseValidation(clientOptions.responseValidation) + .timeout(clientOptions.timeout) + .build() + fun builder() = Builder() } - class 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: Duration? = null + private var timeout: Timeout? = null fun responseValidation(responseValidation: Boolean) = apply { this.responseValidation = responseValidation } - fun timeout(timeout: Duration) = apply { this.timeout = timeout } + fun timeout(timeout: Timeout) = apply { this.timeout = timeout } - fun build(): RequestOptions { - return RequestOptions(responseValidation, timeout) - } + fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build()) + + fun build(): RequestOptions = RequestOptions(responseValidation, timeout) } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Sleeper.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Sleeper.kt new file mode 100644 index 00000000..142bc896 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Sleeper.kt @@ -0,0 +1,17 @@ +package com.braintrustdata.api.core + +import java.time.Duration + +/** + * 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]. */ + suspend fun sleepAsync(duration: Duration) +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Timeout.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Timeout.kt new file mode 100644 index 00000000..675badfe --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Timeout.kt @@ -0,0 +1,155 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +import java.time.Duration +import java.util.Objects + +/** 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 { + + fun default() = builder().build() + + /** Returns a mutable builder for constructing an instance of [Timeout]. */ + 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 + + 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 } + + /** + * 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 } + + /** + * 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 } + + /** + * 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 } + + /** + * 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) + } + + 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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Utils.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Utils.kt index 2696a957..c87fbaa1 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Utils.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Utils.kt @@ -3,54 +3,100 @@ package com.braintrustdata.api.core import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.google.common.collect.ImmutableListMultimap -import com.google.common.collect.ListMultimap -import com.google.common.collect.Multimaps import java.util.Collections +import java.util.SortedMap +import java.util.concurrent.locks.Lock -internal fun T?.getOrThrow(name: String): T { - if (this == null) { - throw BraintrustInvalidDataException("'${name}' is not present") - } +internal fun T?.getOrThrow(name: String): T = + this ?: throw BraintrustInvalidDataException("`${name}` is not present") - return this -} +internal fun List.toImmutable(): List = + if (isEmpty()) Collections.emptyList() else Collections.unmodifiableList(toList()) -internal fun List.toUnmodifiable(): List { - if (isEmpty()) { - return Collections.emptyList() - } +internal fun Map.toImmutable(): Map = + if (isEmpty()) immutableEmptyMap() else Collections.unmodifiableMap(toMap()) - return Collections.unmodifiableList(this) -} +internal fun immutableEmptyMap(): Map = Collections.emptyMap() -internal fun Map.toUnmodifiable(): Map { - if (isEmpty()) { - return Collections.emptyMap() - } +internal fun , V> SortedMap.toImmutable(): SortedMap = + if (isEmpty()) Collections.emptySortedMap() + else Collections.unmodifiableSortedMap(toSortedMap(comparator())) - return Collections.unmodifiableMap(this) -} +/** + * 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. + */ +internal fun > Sequence.allMaxBy(selector: (T) -> R): List { + var maxValue: R? = null + val maxElements = mutableListOf() -internal fun ListMultimap.toUnmodifiable(): ListMultimap { - if (isEmpty()) { - return ImmutableListMultimap.of() + 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 Multimaps.unmodifiableListMultimap(this) + return maxElements } -internal fun ListMultimap.getRequiredHeader(header: String): String { - val value = - entries() - .stream() - .filter { entry -> entry.key.equals(header, ignoreCase = true) } - .map { entry -> entry.value } - .findFirst() - if (!value.isPresent) { - throw BraintrustInvalidDataException("Could not find $header header") +/** + * 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. + */ +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. + */ +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. + */ +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 value.get() + return string } internal interface Enum + +/** + * Executes a suspending block of code while holding this lock. + * + * @param T the return type of the action + * @param action the suspending function to execute while holding the lock + * @return the result of executing the action + */ +internal suspend fun Lock.withLockAsync(action: suspend () -> T): T { + lock() + return try { + action() + } finally { + unlock() + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Values.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Values.kt index 964db27d..5cfc6aa4 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Values.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/Values.kt @@ -2,8 +2,6 @@ package com.braintrustdata.api.core import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.fasterxml.jackson.annotation.JacksonAnnotationsInside -import com.fasterxml.jackson.annotation.JsonAutoDetect -import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.core.JsonGenerator @@ -28,76 +26,140 @@ 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.fasterxml.jackson.module.kotlin.jacksonTypeRef -import java.nio.charset.Charset -import java.util.Objects +import java.io.InputStream +import java.util.* import kotlin.reflect.KClass -import org.apache.hc.core5.http.ContentType +/** + * 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 - fun asKnown(): T? = - when (this) { - is KnownValue -> value - else -> null - } + /** + * Returns this field's "known" value, meaning it matches the type the SDK expects, or null if + * this field contains an arbitrary [JsonValue]. + * + * This is the opposite of [asUnknown]. + */ + fun asKnown(): T? = (this as? KnownValue)?.value /** - * If the "known" value (i.e. matching the type that the SDK expects) is returned by the API - * then this method will return `null`, otherwise a `JsonValue` is returned. + * Returns this field's arbitrary [JsonValue], meaning it mismatches the type the SDK expects, + * or null if this field contains a "known" value. + * + * This is the opposite of [asKnown]. */ - fun asUnknown(): JsonValue? = - when (this) { - is JsonValue -> this - else -> null - } + fun asUnknown(): JsonValue? = this as? JsonValue + /** + * Returns this field's boolean value, or null if it doesn't contain a boolean. + * + * This method checks for both a [KnownValue] containing a boolean and for [JsonBoolean]. + */ fun asBoolean(): Boolean? = when (this) { is JsonBoolean -> value + is KnownValue -> value as? Boolean else -> null } + /** + * Returns this field's numerical value, or null if it doesn't contain a number. + * + * This method checks for both a [KnownValue] containing a number and for [JsonNumber]. + */ fun asNumber(): Number? = when (this) { is JsonNumber -> value + is KnownValue -> value as? Number else -> null } + /** + * Returns this field's string value, or null if it doesn't contain a string. + * + * This method checks for both a [KnownValue] containing a string and for [JsonString]. + */ fun asString(): String? = when (this) { is JsonString -> value + is KnownValue -> value as? String else -> null } fun asStringOrThrow(): String = - when (this) { - is JsonString -> value - else -> throw BraintrustInvalidDataException("Value is not a string") - } + asString() ?: throw BraintrustInvalidDataException("Value is not a string") + /** + * Returns this field's list value, or null if it doesn't contain a list. + * + * This method checks for both a [KnownValue] containing a list and for [JsonArray]. + */ fun asArray(): List? = when (this) { is JsonArray -> values + is KnownValue -> + (value as? List<*>)?.map { + try { + JsonValue.from(it) + } catch (e: IllegalArgumentException) { + // The known value is a list, but not all items are convertible to + // `JsonValue`. + return null + } + } else -> null } + /** + * Returns this field's map value, or null if it doesn't contain a map. + * + * This method checks for both a [KnownValue] containing a map and for [JsonObject]. + */ fun asObject(): Map? = when (this) { is JsonObject -> values + is KnownValue -> + (value as? Map<*, *>) + ?.map { (key, value) -> + if (key !is String) { + return null + } + + val jsonValue = + try { + JsonValue.from(value) + } catch (e: IllegalArgumentException) { + // The known value is a map, but not all values are convertible to + // `JsonValue`. + return null + } + + key to jsonValue + } + ?.toMap() else -> null } internal fun getRequired(name: String): T = when (this) { is KnownValue -> value - is JsonMissing -> throw BraintrustInvalidDataException("'${name}' is not set") - is JsonNull -> throw BraintrustInvalidDataException("'${name}' is null") - else -> throw BraintrustInvalidDataException("'${name}' is invalid, received ${this}") + is JsonMissing -> throw BraintrustInvalidDataException("`$name` is not set") + is JsonNull -> throw BraintrustInvalidDataException("`$name` is null") + else -> throw BraintrustInvalidDataException("`$name` is invalid, received $this") } internal fun getNullable(name: String): T? = @@ -105,7 +167,7 @@ sealed class JsonField { is KnownValue -> value is JsonMissing -> null is JsonNull -> null - else -> throw BraintrustInvalidDataException("'${name}' is invalid, received ${this}") + else -> throw BraintrustInvalidDataException("`$name` is invalid, received $this") } internal fun map(transform: (T) -> R): JsonField = @@ -114,19 +176,35 @@ sealed class JsonField { is JsonValue -> this } + internal fun accept(consume: (T) -> Unit) { + asKnown()?.let(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]. */ fun of(value: T): JsonField = KnownValue.of(value) + /** + * Returns a [JsonField] containing the given "known" [value], or [JsonNull] if [value] is + * null. + */ fun ofNullable(value: T?): JsonField = when (value) { null -> JsonNull.of() @@ -134,10 +212,16 @@ sealed class JsonField { } } - // 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 + /** + * 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) : @@ -146,21 +230,22 @@ sealed class JsonField { override fun createContextual( context: DeserializationContext, property: BeanProperty?, - ): JsonDeserializer> { - return Deserializer(context.contextualType?.containedType(0)) - } + ): JsonDeserializer> = Deserializer(context.contextualType?.containedType(0)) - override fun ObjectCodec.deserialize(node: JsonNode): JsonField<*> { - return type?.let { tryDeserialize(node, type) }?.let { of(it) } + override fun ObjectCodec.deserialize(node: JsonNode): JsonField<*> = + type?.let { tryDeserialize(node, type) }?.let { of(it) } ?: JsonValue.fromJsonNode(node) - } - override fun getNullValue(context: DeserializationContext): JsonField<*> { - return JsonNull.of() - } + 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() { @@ -170,6 +255,7 @@ sealed class JsonValue : JsonField() { fun convert(type: KClass): R? = JSON_MAPPER.convertValue(this, type.java) + /** 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() @@ -181,7 +267,12 @@ sealed class JsonValue : JsonField() { 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() @@ -196,15 +287,52 @@ sealed class JsonValue : JsonField() { fun visitObject(values: Map): R = visitDefault() - fun visitDefault(): R { - throw RuntimeException("Unexpected value") - } + /** + * 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: + * ```kotlin + * // Create primitive JSON values + * val nullValue: JsonValue = JsonValue.from(null) + * val booleanValue: JsonValue = JsonValue.from(true) + * val numberValue: JsonValue = JsonValue.from(42) + * val stringValue: JsonValue = JsonValue.from("Hello World!") + * + * // Create a JSON array value equivalent to `["Hello", "World"]` + * val arrayValue: JsonValue = JsonValue.from(listOf("Hello", "World")) + * + * // Create a JSON object value equivalent to `{ "a": 1, "b": 2 }` + * val objectValue: JsonValue = JsonValue.from(mapOf( + * "a" to 1, + * "b" to 2, + * )) + * + * // Create an arbitrarily nested JSON equivalent to: + * // { + * // "a": [1, 2], + * // "b": [3, 4] + * // } + * val complexValue: JsonValue = JsonValue.from(mapOf( + * "a" to listOf(1, 2), + * "b" to listOf(3, 4), + * )) + * ``` + * + * @throws IllegalArgumentException if [value] is not JSON serializable. + */ fun from(value: Any?): JsonValue = when (value) { null -> JsonNull.of() @@ -212,6 +340,11 @@ sealed class JsonValue : JsonField() { else -> JSON_MAPPER.convertValue(value, JsonValue::class.java) } + /** + * Returns a [JsonValue] converted from the given Jackson [JsonNode]. + * + * @throws IllegalStateException for unsupported node types. + */ fun fromJsonNode(node: JsonNode): JsonValue = when (node.nodeType) { MISSING -> JsonMissing.of() @@ -232,16 +365,19 @@ sealed class JsonValue : JsonField() { } class Deserializer : BaseDeserializer(JsonValue::class) { - override fun ObjectCodec.deserialize(node: JsonNode): JsonValue { - return fromJsonNode(node) - } - override fun getNullValue(context: DeserializationContext?): JsonValue { - return JsonNull.of() - } + 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 @@ -252,52 +388,67 @@ private constructor( return true } - return other is KnownValue<*> && value == other.value + return other is KnownValue<*> && value contentEquals other.value } - override fun hashCode() = value.hashCode() + override fun hashCode() = contentHash(value) - override fun toString() = value.toString() + override fun toString() = value.contentToString() companion object { + + /** Returns a [KnownValue] containing the given [value]. */ @JsonCreator 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]. */ fun of() = INSTANCE } class Serializer : BaseSerializer(JsonMissing::class) { + override fun serialize( value: JsonMissing, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { - throw RuntimeException("JsonMissing cannot be serialized") + 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 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 @@ -316,14 +467,18 @@ private constructor( override fun toString() = value.toString() companion object { + + /** Returns a [JsonBoolean] containing the given [value]. */ @JsonCreator 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 @@ -337,10 +492,13 @@ private constructor( override fun toString() = value.toString() companion object { + + /** Returns a [JsonNumber] containing the given [value]. */ @JsonCreator 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 @@ -359,10 +517,13 @@ private constructor( override fun toString() = value companion object { + + /** Returns a [JsonString] containing the given [value]. */ @JsonCreator fun of(value: String) = JsonString(value) } } +/** A [JsonValue] representing a JSON array value. */ class JsonArray private constructor( @get:com.fasterxml.jackson.annotation.JsonValue @@ -383,10 +544,13 @@ private constructor( override fun toString() = values.toString() companion object { - @JsonCreator fun of(values: List) = JsonArray(values.toUnmodifiable()) + + /** Returns a [JsonArray] containing the given [values]. */ + @JsonCreator fun of(values: List) = JsonArray(values.toImmutable()) } } +/** A [JsonValue] representing a JSON object value. */ class JsonObject private constructor( @get:com.fasterxml.jackson.annotation.JsonValue @@ -407,123 +571,124 @@ private constructor( override fun toString() = values.toString() companion object { - @JsonCreator fun of(values: Map) = JsonObject(values.toUnmodifiable()) + + /** Returns a [JsonObject] containing the given [values]. */ + @JsonCreator 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, -) +@JsonInclude(JsonInclude.Include.CUSTOM, valueFilter = JsonField.IsMissing::class) annotation class ExcludeMissing -@JacksonAnnotationsInside -@JsonAutoDetect( - getterVisibility = Visibility.NONE, - isGetterVisibility = Visibility.NONE, - setterVisibility = Visibility.NONE, - creatorVisibility = Visibility.NONE, - fieldVisibility = Visibility.NONE -) -annotation class NoAutoDetect - -class MultipartFormValue -internal constructor( - val name: String, - val value: T, - val contentType: ContentType, - val filename: String? = null +/** 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 val value: JsonField, + /** A content type for the serialized parts. */ + val contentType: String, + /** Returns the filename directive that will be included in the serialized field. */ + val filename: String?, ) { - private var hashCode: Int = 0 - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - contentType, - filename, - when (value) { - is ByteArray -> value.contentHashCode() - is String -> value - is Boolean -> value - is Long -> value - is Double -> value - else -> value?.hashCode() - } - ) - } - return hashCode - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this.javaClass != other.javaClass) return false - - other as MultipartFormValue<*> + companion object { - if (name != other.name || contentType != other.contentType || filename != other.filename) - return false + /** + * 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. + */ + 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. + */ + fun of(value: JsonField) = builder().value(value).build() + + /** + * Returns a mutable builder for constructing an instance of [MultipartField]. + * + * The following fields are required: + * ```kotlin + * .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. + */ + fun builder() = Builder() + } - return when { - value is ByteArray && other.value is ByteArray -> value contentEquals other.value - else -> value?.equals(other.value) ?: (other.value == null) + 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 } + + /** + * Returns an immutable instance of [MultipartField]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .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, + ) } } - override fun toString(): String { - return "MultipartFormValue(name='$name', contentType=$contentType, filename=$filename, value=${valueToString()})" - } + private val hashCode: Int by lazy { contentHash(value, contentType, filename) } - private fun valueToString(): String = - when (value) { - is ByteArray -> "ByteArray of size ${value.size}" - else -> value.toString() + override fun hashCode(): Int = hashCode + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - companion object { - internal fun fromString( - name: String, - value: String, - contentType: ContentType - ): MultipartFormValue = MultipartFormValue(name, value, contentType) - - internal fun fromBoolean( - name: String, - value: Boolean, - contentType: ContentType, - ): MultipartFormValue = MultipartFormValue(name, value, contentType) - - internal fun fromLong( - name: String, - value: Long, - contentType: ContentType, - ): MultipartFormValue = MultipartFormValue(name, value, contentType) - - internal fun fromDouble( - name: String, - value: Double, - contentType: ContentType, - ): MultipartFormValue = MultipartFormValue(name, value, contentType) - - internal fun fromEnum( - name: String, - value: T, - contentType: ContentType - ): MultipartFormValue = MultipartFormValue(name, value, contentType) - - internal fun fromByteArray( - name: String, - value: ByteArray, - contentType: ContentType, - filename: String? = null - ): MultipartFormValue = MultipartFormValue(name, value, contentType, filename) + return other is MultipartField<*> && + value == other.value && + contentType == other.contentType && + filename == other.filename } -} -internal object ContentTypes { - val DefaultText = ContentType.create(ContentType.TEXT_PLAIN.mimeType, Charset.forName("UTF-8")) - val DefaultBinary = ContentType.DEFAULT_BINARY + override fun toString(): String = + "MultipartField{value=$value, contentType=$contentType, filename=$filename}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/ErrorHandler.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/ErrorHandler.kt new file mode 100644 index 00000000..cef11a9b --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/ErrorHandler.kt @@ -0,0 +1,80 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core.handlers + +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.http.HttpResponse +import com.braintrustdata.api.core.http.HttpResponse.Handler +import com.braintrustdata.api.errors.BadRequestException +import com.braintrustdata.api.errors.InternalServerException +import com.braintrustdata.api.errors.NotFoundException +import com.braintrustdata.api.errors.PermissionDeniedException +import com.braintrustdata.api.errors.RateLimitException +import com.braintrustdata.api.errors.UnauthorizedException +import com.braintrustdata.api.errors.UnexpectedStatusCodeException +import com.braintrustdata.api.errors.UnprocessableEntityException +import com.fasterxml.jackson.databind.json.JsonMapper + +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() + } + } +} + +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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/JsonHandler.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/JsonHandler.kt new file mode 100644 index 00000000..b0c897be --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/JsonHandler.kt @@ -0,0 +1,20 @@ +@file:JvmName("JsonHandler") + +package com.braintrustdata.api.core.handlers + +import com.braintrustdata.api.core.http.HttpResponse +import com.braintrustdata.api.core.http.HttpResponse.Handler +import com.braintrustdata.api.errors.BraintrustInvalidDataException +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef + +internal inline fun jsonHandler(jsonMapper: JsonMapper): Handler = + object : Handler { + override fun handle(response: HttpResponse): T { + try { + return jsonMapper.readValue(response.body(), jacksonTypeRef()) + } catch (e: Exception) { + throw BraintrustInvalidDataException("Error reading response", e) + } + } + } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/StringHandler.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/StringHandler.kt new file mode 100644 index 00000000..b685a9eb --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/handlers/StringHandler.kt @@ -0,0 +1,13 @@ +@file:JvmName("StringHandler") + +package com.braintrustdata.api.core.handlers + +import com.braintrustdata.api.core.http.HttpResponse +import com.braintrustdata.api.core.http.HttpResponse.Handler + +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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/BinaryResponseContent.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/BinaryResponseContent.kt deleted file mode 100755 index 324cfe2d..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/BinaryResponseContent.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.braintrustdata.api.core.http - -import java.io.IOException -import java.io.InputStream -import java.io.OutputStream -import java.lang.AutoCloseable - -interface BinaryResponseContent : AutoCloseable { - - fun contentType(): String? - - fun body(): InputStream - - @Throws(IOException::class) fun writeTo(outputStream: OutputStream) -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/Headers.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/Headers.kt new file mode 100644 index 00000000..d40af129 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/Headers.kt @@ -0,0 +1,111 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core.http + +import com.braintrustdata.api.core.JsonArray +import com.braintrustdata.api.core.JsonBoolean +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonNumber +import com.braintrustdata.api.core.JsonObject +import com.braintrustdata.api.core.JsonString +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.toImmutable +import java.util.TreeMap + +class Headers private constructor(private val map: Map>, 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 { + + 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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequest.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequest.kt index e6f7a0a5..e43325c4 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequest.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequest.kt @@ -1,91 +1,144 @@ package com.braintrustdata.api.core.http -import com.braintrustdata.api.core.toUnmodifiable -import com.google.common.collect.ArrayListMultimap -import com.google.common.collect.ListMultimap -import com.google.common.collect.Multimap -import com.google.common.collect.MultimapBuilder +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable class HttpRequest private constructor( val method: HttpMethod, - val url: String?, + val baseUrl: String, val pathSegments: List, - val queryParams: ListMultimap, - val headers: ListMultimap, + val headers: Headers, + val queryParams: QueryParams, val body: HttpRequestBody?, ) { + fun toBuilder(): Builder = Builder().from(this) + override fun toString(): String = - "HttpRequest {method=$method, pathSegments=$pathSegments, queryParams=$queryParams, headers=$headers, body=$body}" + "HttpRequest{method=$method, baseUrl=$baseUrl, pathSegments=$pathSegments, headers=$headers, queryParams=$queryParams, body=$body}" companion object { fun builder() = Builder() } - class Builder { + class Builder internal constructor() { private var method: HttpMethod? = null - private var url: String? = null - private var pathSegments: MutableList = ArrayList() - private var queryParams: ListMultimap = ArrayListMultimap.create() + 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 - private var headers: ListMultimap = - MultimapBuilder.treeKeys(String.CASE_INSENSITIVE_ORDER).arrayListValues().build() + + 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 url(url: String) = apply { this.url = url } + fun baseUrl(baseUrl: String) = apply { this.baseUrl = baseUrl } - fun addPathSegment(pathSegment: String) = apply { this.pathSegments.add(pathSegment) } + fun addPathSegment(pathSegment: String) = apply { pathSegments.add(pathSegment) } fun addPathSegments(vararg pathSegments: String) = apply { - for (pathSegment in pathSegments) { - this.pathSegments.add(pathSegment) - } + this.pathSegments.addAll(pathSegments) } - fun putQueryParam(name: String, value: String) = apply { - this.queryParams.replaceValues(name, listOf(value)) + fun headers(headers: Headers) = apply { + this.headers.clear() + putAllHeaders(headers) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.queryParams.replaceValues(name, values) + fun headers(headers: Map>) = apply { + this.headers.clear() + putAllHeaders(headers) } - fun putAllQueryParams(queryParams: Map>) = apply { - queryParams.forEach(this::putQueryParams) + 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 putAllQueryParams(queryParams: Multimap) = apply { - queryParams.asMap().forEach(this::putQueryParams) + fun replaceHeaders(name: String, value: String) = apply { headers.replace(name, value) } + + fun replaceHeaders(name: String, values: Iterable) = apply { + headers.replace(name, values) } - fun putHeader(name: String, value: String) = apply { - this.headers.replaceValues(name, listOf(value)) + fun replaceAllHeaders(headers: Headers) = apply { this.headers.replaceAll(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + this.headers.replaceAll(headers) } - fun putHeaders(name: String, values: Iterable) = apply { - this.headers.replaceValues(name, values) + 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 putAllHeaders(headers: Map>) = apply { - headers.forEach(this::putHeaders) + fun queryParams(queryParams: Map>) = apply { + this.queryParams.clear() + putAllQueryParams(queryParams) } - fun putAllHeaders(headers: Multimap) = apply { - headers.asMap().forEach(this::putHeaders) + 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( - checkNotNull(method) { "`method` is required but was not set" }, - url, - pathSegments.toUnmodifiable(), - queryParams.toUnmodifiable(), - headers, + checkRequired("method", method), + checkRequired("baseUrl", baseUrl), + pathSegments.toImmutable(), + headers.build(), + queryParams.build(), body, ) } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequestBodies.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequestBodies.kt new file mode 100644 index 00000000..5db0438b --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequestBodies.kt @@ -0,0 +1,125 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core.http + +import com.braintrustdata.api.core.MultipartField +import com.braintrustdata.api.errors.BraintrustInvalidDataException +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.databind.node.JsonNodeType +import java.io.InputStream +import java.io.OutputStream +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder +import org.apache.hc.core5.http.ContentType +import org.apache.hc.core5.http.HttpEntity + +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() {} + } + +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() + 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, + ) + } + } + } + .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 BraintrustInvalidDataException( + "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 BraintrustInvalidDataException( + "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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequestBody.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequestBody.kt index e5c7df37..15a5fed0 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequestBody.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpRequestBody.kt @@ -1,12 +1,11 @@ package com.braintrustdata.api.core.http -import java.io.IOException import java.io.OutputStream import java.lang.AutoCloseable interface HttpRequestBody : AutoCloseable { - @Throws(IOException::class) fun writeTo(outputStream: OutputStream) + fun writeTo(outputStream: OutputStream) fun contentType(): String? @@ -20,6 +19,4 @@ interface HttpRequestBody : AutoCloseable { * streamed. In this case the body data isn't available on subsequent attempts. */ fun repeatable(): Boolean - - override fun close() } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpResponse.kt index 333dda67..913fab15 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpResponse.kt @@ -1,14 +1,14 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.core.http -import com.google.common.collect.ListMultimap import java.io.InputStream -import java.lang.AutoCloseable interface HttpResponse : AutoCloseable { fun statusCode(): Int - fun headers(): ListMultimap + fun headers(): Headers fun body(): InputStream diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpResponseFor.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpResponseFor.kt new file mode 100644 index 00000000..6c604817 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/HttpResponseFor.kt @@ -0,0 +1,24 @@ +package com.braintrustdata.api.core.http + +import java.io.InputStream + +interface HttpResponseFor : HttpResponse { + + fun parse(): T +} + +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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/PhantomReachableClosingHttpClient.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/PhantomReachableClosingHttpClient.kt new file mode 100644 index 00000000..853de3d7 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/PhantomReachableClosingHttpClient.kt @@ -0,0 +1,25 @@ +package com.braintrustdata.api.core.http + +import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.closeWhenPhantomReachable + +/** + * 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 suspend fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse = httpClient.executeAsync(request, requestOptions) + + override fun close() = httpClient.close() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/PhantomReachableClosingStreamResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/PhantomReachableClosingStreamResponse.kt new file mode 100644 index 00000000..571d7bc4 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/PhantomReachableClosingStreamResponse.kt @@ -0,0 +1,20 @@ +package com.braintrustdata.api.core.http + +import com.braintrustdata.api.core.closeWhenPhantomReachable + +/** + * 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 asSequence(): Sequence = streamResponse.asSequence() + + override fun close() = streamResponse.close() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/QueryParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/QueryParams.kt new file mode 100644 index 00000000..7647320b --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/QueryParams.kt @@ -0,0 +1,125 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core.http + +import com.braintrustdata.api.core.JsonArray +import com.braintrustdata.api.core.JsonBoolean +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonNumber +import com.braintrustdata.api.core.JsonObject +import com.braintrustdata.api.core.JsonString +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.toImmutable + +class QueryParams private constructor(private val map: Map>, 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 { + + 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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/RetryingHttpClient.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/RetryingHttpClient.kt index 89e150b4..a9fde6f1 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/RetryingHttpClient.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/RetryingHttpClient.kt @@ -1,9 +1,11 @@ -@file:JvmSynthetic - package com.braintrustdata.api.core.http +import com.braintrustdata.api.core.DefaultSleeper import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.Sleeper +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustIoException +import com.braintrustdata.api.errors.BraintrustRetryableException import java.io.IOException import java.time.Clock import java.time.Duration @@ -16,55 +18,54 @@ import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.TimeUnit import kotlin.math.min import kotlin.math.pow -import kotlin.time.toKotlinDuration -import kotlinx.coroutines.delay 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 { + override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { if (!isRetryable(request) || maxRetries <= 0) { return httpClient.execute(request, requestOptions) } - maybeAddIdempotencyHeader(request) + var modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. - val shouldSendRetryCount = !request.headers.containsKey("x-stainless-retry-count") + val shouldSendRetryCount = + !modifiedRequest.headers.names().contains("X-Stainless-Retry-Count") var retries = 0 while (true) { if (shouldSendRetryCount) { - setRetryCountHeader(request, retries) + modifiedRequest = setRetryCountHeader(modifiedRequest, retries) } val response = try { - val response = httpClient.execute(request, requestOptions) + val response = httpClient.execute(modifiedRequest, requestOptions) if (++retries > maxRetries || !shouldRetry(response)) { return response } response - } catch (t: Throwable) { - if (++retries > maxRetries || !shouldRetry(t)) { - throw t + } catch (throwable: Throwable) { + if (++retries > maxRetries || !shouldRetry(throwable)) { + throw throwable } null } - val backoffMillis = getRetryBackoffMillis(retries, response) - Thread.sleep(backoffMillis.toMillis()) + val backoffDuration = getRetryBackoffDuration(retries, response) + // All responses must be closed, so close the failed one before retrying. + response?.close() + sleeper.sleep(backoffDuration) } } @@ -76,66 +77,72 @@ private constructor( return httpClient.executeAsync(request, requestOptions) } - maybeAddIdempotencyHeader(request) + var modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. - val shouldSendRetryCount = !request.headers.containsKey("x-stainless-retry-count") + val shouldSendRetryCount = + !modifiedRequest.headers.names().contains("X-Stainless-Retry-Count") var retries = 0 while (true) { if (shouldSendRetryCount) { - setRetryCountHeader(request, retries) + modifiedRequest = setRetryCountHeader(modifiedRequest, retries) } val response = try { - val response = httpClient.execute(request, requestOptions) + val response = httpClient.execute(modifiedRequest, requestOptions) if (++retries > maxRetries || !shouldRetry(response)) { return response } response - } catch (t: Throwable) { - if (++retries > maxRetries || !shouldRetry(t)) { - throw t + } catch (throwable: Throwable) { + if (++retries > maxRetries || !shouldRetry(throwable)) { + throw throwable } null } - val backoffMillis = getRetryBackoffMillis(retries, response) - delay(backoffMillis.toKotlinDuration()) + val backoffDuration = getRetryBackoffDuration(retries, response) + // All responses must be closed, so close the failed one before retrying. + response?.close() + sleeper.sleepAsync(backoffDuration) } } override fun close() { httpClient.close() + sleeper.close() } - private fun isRetryable(request: HttpRequest): Boolean { + 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. - return request.body?.repeatable() ?: true - } + request.body?.repeatable() ?: true - private fun setRetryCountHeader(request: HttpRequest, retries: Int) { - request.headers.removeAll("x-stainless-retry-count") - request.headers.put("x-stainless-retry-count", retries.toString()) - } + 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) { - if (idempotencyHeader != null && !request.headers.containsKey(idempotencyHeader)) { - // Set a header to uniquely identify the request when retried - request.headers.put(idempotencyHeader, idempotencyKey()) + 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().get("x-should-retry").getOrNull(0) + val shouldRetryHeader = response.headers().values("X-Should-Retry").getOrNull(0) val statusCode = response.statusCode() return when { @@ -155,32 +162,32 @@ private constructor( } } - private fun shouldRetry(throwable: Throwable): Boolean { - // Only retry IOException and BraintrustIoException, other exceptions are not intended to be - // retried. - return throwable is IOException || throwable is BraintrustIoException - } + private fun shouldRetry(throwable: Throwable): Boolean = + // Only retry known retryable exceptions, other exceptions are not intended to be retried. + throwable is IOException || + throwable is BraintrustIoException || + throwable is BraintrustRetryableException - private fun getRetryBackoffMillis(retries: Int, response: HttpResponse?): Duration { + 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 - .get("Retry-After-Ms") + .values("Retry-After-Ms") .getOrNull(0) ?.toFloatOrNull() ?.times(TimeUnit.MILLISECONDS.toNanos(1)) - ?: headers.get("Retry-After").getOrNull(0)?.let { retryAfter -> + ?: 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 - ) + DateTimeFormatter.RFC_1123_DATE_TIME, + ), ) } catch (e: DateTimeParseException) { null @@ -207,18 +214,22 @@ private constructor( } companion object { + fun builder() = Builder() } - class 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 } @@ -227,7 +238,8 @@ private constructor( fun build(): HttpClient = RetryingHttpClient( - checkNotNull(httpClient) { "`httpClient` is required but was not set" }, + checkRequired("httpClient", httpClient), + sleeper ?: DefaultSleeper(), clock, maxRetries, idempotencyHeader, diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/StreamResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/StreamResponse.kt new file mode 100644 index 00000000..4667da50 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/core/http/StreamResponse.kt @@ -0,0 +1,13 @@ +package com.braintrustdata.api.core.http + +interface StreamResponse : AutoCloseable { + + fun asSequence(): Sequence +} + +internal fun StreamResponse.map(transform: (T) -> R): StreamResponse = + object : StreamResponse { + override fun asSequence(): Sequence = this@map.asSequence().map(transform) + + override fun close() = this@map.close() + } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BadRequestException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BadRequestException.kt index a373ba5e..70c8994d 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BadRequestException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BadRequestException.kt @@ -1,9 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class BadRequestException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + BraintrustServiceException("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: + * ```kotlin + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class BadRequestException( - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(400, headers, body, error) + /** + * Returns an immutable instance of [BadRequestException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BadRequestException = + BadRequestException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustError.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustError.kt deleted file mode 100755 index e845c581..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustError.kt +++ /dev/null @@ -1,67 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.errors - -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import java.util.Objects - -@JsonDeserialize(builder = BraintrustError.Builder::class) -@NoAutoDetect -class BraintrustError -constructor( - private val additionalProperties: Map, -) { - - @JsonAnyGetter fun additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder() - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is BraintrustError && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - return Objects.hash(additionalProperties) - } - - override fun toString() = "BraintrustError{additionalProperties=$additionalProperties}" - - companion object { - - @JvmStatic fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - fun from(error: BraintrustError) = apply { - additionalProperties(error.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): BraintrustError = BraintrustError(additionalProperties.toUnmodifiable()) - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustRetryableException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustRetryableException.kt new file mode 100644 index 00000000..77f6d8a3 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustRetryableException.kt @@ -0,0 +1,13 @@ +package com.braintrustdata.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 BraintrustRetryableException constructor(message: String? = null, cause: Throwable? = null) : + BraintrustException(message, cause) diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustServiceException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustServiceException.kt index 4838237f..ebb6267b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustServiceException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/BraintrustServiceException.kt @@ -1,21 +1,17 @@ -package com.braintrustdata.api.errors +// File generated from our OpenAPI spec by Stainless. -import com.google.common.collect.ListMultimap +package com.braintrustdata.api.errors -abstract class BraintrustServiceException( - private val statusCode: Int, - private val headers: ListMultimap, - private val body: String, - private val error: BraintrustError, - message: String = "$statusCode: $error", - cause: Throwable? = null -) : BraintrustException(message, cause) { +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.http.Headers - fun statusCode(): Int = statusCode +abstract class BraintrustServiceException +protected constructor(message: String, cause: Throwable? = null) : + BraintrustException(message, cause) { - fun headers(): ListMultimap = headers + abstract fun statusCode(): Int - fun body(): String = body + abstract fun headers(): Headers - fun error(): BraintrustError = error + abstract fun body(): JsonValue } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/InternalServerException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/InternalServerException.kt index e43239e8..bb807770 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/InternalServerException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/InternalServerException.kt @@ -1,10 +1,85 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class InternalServerException +private constructor( + private val statusCode: Int, + private val headers: Headers, + private val body: JsonValue, + cause: Throwable?, +) : BraintrustServiceException("$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: + * ```kotlin + * .statusCode() + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class InternalServerException( - statusCode: Int, - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(statusCode, headers, body, error) + /** + * Returns an immutable instance of [InternalServerException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/NotFoundException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/NotFoundException.kt index 8e879cbf..f8006c63 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/NotFoundException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/NotFoundException.kt @@ -1,9 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class NotFoundException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + BraintrustServiceException("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: + * ```kotlin + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class NotFoundException( - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(404, headers, body, error) + /** + * Returns an immutable instance of [NotFoundException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): NotFoundException = + NotFoundException(checkRequired("headers", headers), checkRequired("body", body), cause) + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/PermissionDeniedException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/PermissionDeniedException.kt index 98c6f33e..da659a48 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/PermissionDeniedException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/PermissionDeniedException.kt @@ -1,9 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class PermissionDeniedException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + BraintrustServiceException("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: + * ```kotlin + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class PermissionDeniedException( - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(403, headers, body, error) + /** + * Returns an immutable instance of [PermissionDeniedException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PermissionDeniedException = + PermissionDeniedException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/RateLimitException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/RateLimitException.kt index d98aed03..bed909e7 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/RateLimitException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/RateLimitException.kt @@ -1,9 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class RateLimitException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + BraintrustServiceException("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: + * ```kotlin + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class RateLimitException( - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(429, headers, body, error) + /** + * Returns an immutable instance of [RateLimitException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RateLimitException = + RateLimitException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnauthorizedException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnauthorizedException.kt index 72236499..d41df33a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnauthorizedException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnauthorizedException.kt @@ -1,9 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class UnauthorizedException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + BraintrustServiceException("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: + * ```kotlin + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class UnauthorizedException( - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(401, headers, body, error) + /** + * Returns an immutable instance of [UnauthorizedException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UnauthorizedException = + UnauthorizedException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnexpectedStatusCodeException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnexpectedStatusCodeException.kt index 7482559f..d4a491fb 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnexpectedStatusCodeException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnexpectedStatusCodeException.kt @@ -1,10 +1,86 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class UnexpectedStatusCodeException +private constructor( + private val statusCode: Int, + private val headers: Headers, + private val body: JsonValue, + cause: Throwable?, +) : BraintrustServiceException("$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: + * ```kotlin + * .statusCode() + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class UnexpectedStatusCodeException( - statusCode: Int, - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(statusCode, headers, body, error) + /** + * Returns an immutable instance of [UnexpectedStatusCodeException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .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/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnprocessableEntityException.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnprocessableEntityException.kt index 095b1fcf..a40d7de7 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnprocessableEntityException.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/errors/UnprocessableEntityException.kt @@ -1,9 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. + package com.braintrustdata.api.errors -import com.google.common.collect.ListMultimap +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers + +class UnprocessableEntityException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + BraintrustServiceException("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: + * ```kotlin + * .headers() + * .body() + * ``` + */ + 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 + + 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 } -class UnprocessableEntityException( - headers: ListMultimap, - body: String, - error: BraintrustError, -) : BraintrustServiceException(422, headers, body, error) + /** + * Returns an immutable instance of [UnprocessableEntityException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UnprocessableEntityException = + UnprocessableEntityException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AISecret.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AISecret.kt new file mode 100644 index 00000000..0383875b --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AISecret.kt @@ -0,0 +1,534 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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.util.Collections +import java.util.Objects + +class AISecret +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val name: JsonField, + private val orgId: JsonField, + private val created: JsonField, + private val metadata: JsonField, + private val previewSecret: JsonField, + private val type: JsonField, + private val updatedAt: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("preview_secret") + @ExcludeMissing + previewSecret: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("updated_at") + @ExcludeMissing + updatedAt: JsonField = JsonMissing.of(), + ) : this(id, name, orgId, created, metadata, previewSecret, type, updatedAt, mutableMapOf()) + + /** + * Unique identifier for the AI secret + * + * @throws BraintrustInvalidDataException 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") + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the organization + * + * @throws BraintrustInvalidDataException 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 orgId(): String = orgId.getRequired("org_id") + + /** + * Date of AI secret creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun previewSecret(): String? = previewSecret.getNullable("preview_secret") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): String? = type.getNullable("type") + + /** + * Date of last AI secret update + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun updatedAt(): OffsetDateTime? = updatedAt.getNullable("updated_at") + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * 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 [previewSecret]. + * + * Unlike [previewSecret], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("preview_secret") + @ExcludeMissing + fun _previewSecret(): JsonField = previewSecret + + /** + * 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 [updatedAt]. + * + * Unlike [updatedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("updated_at") + @ExcludeMissing + fun _updatedAt(): JsonField = updatedAt + + @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 [AISecret]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .orgId() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [AISecret]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var name: JsonField? = null + private var orgId: JsonField? = null + private var created: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var previewSecret: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var updatedAt: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(aiSecret: AISecret) = apply { + id = aiSecret.id + name = aiSecret.name + orgId = aiSecret.orgId + created = aiSecret.created + metadata = aiSecret.metadata + previewSecret = aiSecret.previewSecret + type = aiSecret.type + updatedAt = aiSecret.updatedAt + additionalProperties = aiSecret.additionalProperties.toMutableMap() + } + + /** Unique identifier for the AI secret */ + 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 } + + /** Name of the AI secret */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Unique identifier for the organization */ + fun orgId(orgId: String) = orgId(JsonField.of(orgId)) + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgId(orgId: JsonField) = apply { this.orgId = orgId } + + /** Date of AI secret creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } + + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 previewSecret(previewSecret: String?) = + previewSecret(JsonField.ofNullable(previewSecret)) + + /** + * Sets [Builder.previewSecret] to an arbitrary JSON value. + * + * You should usually call [Builder.previewSecret] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun previewSecret(previewSecret: JsonField) = apply { + this.previewSecret = previewSecret + } + + fun type(type: String?) = type(JsonField.ofNullable(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 } + + /** Date of last AI secret update */ + fun updatedAt(updatedAt: OffsetDateTime?) = updatedAt(JsonField.ofNullable(updatedAt)) + + /** + * Sets [Builder.updatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.updatedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun updatedAt(updatedAt: JsonField) = apply { this.updatedAt = updatedAt } + + 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 [AISecret]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .orgId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AISecret = + AISecret( + checkRequired("id", id), + checkRequired("name", name), + checkRequired("orgId", orgId), + created, + metadata, + previewSecret, + type, + updatedAt, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AISecret = apply { + if (validated) { + return@apply + } + + id() + name() + orgId() + created() + metadata()?.validate() + previewSecret() + type() + updatedAt() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (if (previewSecret.asKnown() == null) 0 else 1) + + (if (type.asKnown() == null) 0 else 1) + + (if (updatedAt.asKnown() == null) 0 else 1) + + 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]. */ + fun builder() = Builder() + } + + /** A builder for [Metadata]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AISecret && + id == other.id && + name == other.name && + orgId == other.orgId && + created == other.created && + metadata == other.metadata && + previewSecret == other.previewSecret && + type == other.type && + updatedAt == other.updatedAt && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + orgId, + created, + metadata, + previewSecret, + type, + updatedAt, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AISecret{id=$id, name=$name, orgId=$orgId, created=$created, metadata=$metadata, previewSecret=$previewSecret, type=$type, updatedAt=$updatedAt, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Acl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Acl.kt index bd1188c6..af9cd8dc 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Acl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Acl.kt @@ -2,20 +2,18 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects /** @@ -28,652 +26,541 @@ import java.util.Objects * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the * ACL, as part of a direct permission grant or as part of a role. */ -@JsonDeserialize(builder = Acl.Builder::class) -@NoAutoDetect class Acl +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val objectType: JsonField, + private val _objectOrgId: JsonField, private val objectId: JsonField, - private val userId: JsonField, + private val objectType: JsonField, + private val created: JsonField, private val groupId: JsonField, private val permission: JsonField, - private val restrictObjectType: JsonField, + private val restrictObjectType: JsonField, private val roleId: JsonField, - private val _objectOrgId: JsonField, - private val created: JsonField, - private val additionalProperties: Map, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_object_org_id") + @ExcludeMissing + _objectOrgId: JsonField = JsonMissing.of(), + @JsonProperty("object_id") @ExcludeMissing objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + @JsonProperty("role_id") @ExcludeMissing roleId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( + id, + _objectOrgId, + objectId, + objectType, + created, + groupId, + permission, + restrictObjectType, + roleId, + userId, + mutableMapOf(), + ) - /** Unique identifier for the acl */ + /** + * Unique identifier for the acl + * + * @throws BraintrustInvalidDataException 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") - /** The object type that the ACL applies to */ - fun objectType(): ObjectType = objectType.getRequired("object_type") + /** + * The organization the ACL's referred object belongs to + * + * @throws BraintrustInvalidDataException 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 _objectOrgId(): String = _objectOrgId.getRequired("_object_org_id") - /** The id of the object the ACL applies to */ + /** + * The id of the object the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 userId(): String? = userId.getNullable("user_id") + fun objectType(): AclObjectType = objectType.getRequired("object_type") + + /** + * Date of acl creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun groupId(): String? = groupId.getNullable("group_id") /** - * Each permission permits a certain type of operation on an object in the system + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun permission(): Permission? = permission.getNullable("permission") - /** The object type that the ACL applies to */ - fun restrictObjectType(): RestrictObjectType? = + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = restrictObjectType.getNullable("restrict_object_type") - /** Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided */ + /** + * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun roleId(): String? = roleId.getNullable("role_id") - /** The organization the ACL's referred object belongs to */ - fun _objectOrgId(): String = _objectOrgId.getRequired("_object_org_id") + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - /** Date of acl creation */ - fun created(): OffsetDateTime? = created.getNullable("created") + /** + * 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 - /** Unique identifier for the acl */ - @JsonProperty("id") @ExcludeMissing fun _id() = id + /** + * Returns the raw JSON value of [_objectOrgId]. + * + * Unlike [_objectOrgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_object_org_id") + @ExcludeMissing + fun __objectOrgId(): JsonField = _objectOrgId - /** The object type that the ACL applies to */ - @JsonProperty("object_type") @ExcludeMissing fun _objectType() = objectType + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") @ExcludeMissing fun _objectId() = objectId + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created /** - * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("group_id") @ExcludeMissing fun _groupId() = groupId + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId /** - * Each permission permits a certain type of operation on an object in the system + * Returns the raw JSON value of [permission]. * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("permission") @ExcludeMissing fun _permission() = permission + @JsonProperty("permission") + @ExcludeMissing + fun _permission(): JsonField = permission - /** The object type that the ACL applies to */ + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an unexpected + * type. + */ @JsonProperty("restrict_object_type") @ExcludeMissing - fun _restrictObjectType() = restrictObjectType + fun _restrictObjectType(): JsonField = restrictObjectType - /** Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided */ - @JsonProperty("role_id") @ExcludeMissing fun _roleId() = roleId + /** + * Returns the raw JSON value of [roleId]. + * + * Unlike [roleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role_id") @ExcludeMissing fun _roleId(): JsonField = roleId - /** The organization the ACL's referred object belongs to */ - @JsonProperty("_object_org_id") @ExcludeMissing fun __objectOrgId() = _objectOrgId + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId - /** Date of acl creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Acl = apply { - if (!validated) { - id() - objectType() - objectId() - userId() - groupId() - permission() - restrictObjectType() - roleId() - _objectOrgId() - created() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Acl && - this.id == other.id && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.userId == other.userId && - this.groupId == other.groupId && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.roleId == other.roleId && - this._objectOrgId == other._objectOrgId && - this.created == other.created && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - objectType, - objectId, - userId, - groupId, - permission, - restrictObjectType, - roleId, - _objectOrgId, - created, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Acl{id=$id, objectType=$objectType, objectId=$objectId, userId=$userId, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, _objectOrgId=$_objectOrgId, created=$created, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Acl]. + * + * The following fields are required: + * ```kotlin + * .id() + * ._objectOrgId() + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Acl]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var objectType: JsonField = JsonMissing.of() - private var objectId: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var _objectOrgId: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var created: JsonField = JsonMissing.of() private var groupId: JsonField = JsonMissing.of() private var permission: JsonField = JsonMissing.of() - private var restrictObjectType: JsonField = JsonMissing.of() + private var restrictObjectType: JsonField = JsonMissing.of() private var roleId: JsonField = JsonMissing.of() - private var _objectOrgId: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(acl: Acl) = apply { - this.id = acl.id - this.objectType = acl.objectType - this.objectId = acl.objectId - this.userId = acl.userId - this.groupId = acl.groupId - this.permission = acl.permission - this.restrictObjectType = acl.restrictObjectType - this.roleId = acl.roleId - this._objectOrgId = acl._objectOrgId - this.created = acl.created - additionalProperties(acl.additionalProperties) + id = acl.id + _objectOrgId = acl._objectOrgId + objectId = acl.objectId + objectType = acl.objectType + created = acl.created + groupId = acl.groupId + permission = acl.permission + restrictObjectType = acl.restrictObjectType + roleId = acl.roleId + userId = acl.userId + additionalProperties = acl.additionalProperties.toMutableMap() } /** Unique identifier for the acl */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the acl */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) + /** The organization the ACL's referred object belongs to */ + fun _objectOrgId(_objectOrgId: String) = _objectOrgId(JsonField.of(_objectOrgId)) - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - @ExcludeMissing - fun objectType(objectType: JsonField) = apply { this.objectType = objectType } + /** + * Sets [Builder._objectOrgId] to an arbitrary JSON value. + * + * You should usually call [Builder._objectOrgId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _objectOrgId(_objectOrgId: JsonField) = apply { + this._objectOrgId = _objectOrgId + } /** The id of the object the ACL applies to */ fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") - @ExcludeMissing - fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun userId(userId: String) = userId(JsonField.of(userId)) + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } + + /** Date of acl creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) /** - * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun groupId(groupId: String) = groupId(JsonField.of(groupId)) + fun created(created: JsonField) = apply { this.created = created } /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided */ - @JsonProperty("group_id") - @ExcludeMissing - fun groupId(groupId: JsonField) = apply { this.groupId = groupId } + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) /** - * Each permission permits a certain type of operation on an object in the system + * Sets [Builder.groupId] to an arbitrary JSON value. * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * You should usually call [Builder.groupId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun permission(permission: Permission) = permission(JsonField.of(permission)) + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } + + /** Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided */ + fun permission(permission: Permission?) = permission(JsonField.ofNullable(permission)) /** - * Each permission permits a certain type of operation on an object in the system + * Sets [Builder.permission] to an arbitrary JSON value. * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("permission") - @ExcludeMissing fun permission(permission: JsonField) = apply { this.permission = permission } - /** The object type that the ACL applies to */ - fun restrictObjectType(restrictObjectType: RestrictObjectType) = - restrictObjectType(JsonField.of(restrictObjectType)) + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + */ + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - @ExcludeMissing - fun restrictObjectType(restrictObjectType: JsonField) = apply { + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed [AclObjectType] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { this.restrictObjectType = restrictObjectType } /** * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided */ - fun roleId(roleId: String) = roleId(JsonField.of(roleId)) + fun roleId(roleId: String?) = roleId(JsonField.ofNullable(roleId)) /** - * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * Sets [Builder.roleId] to an arbitrary JSON value. + * + * You should usually call [Builder.roleId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("role_id") - @ExcludeMissing fun roleId(roleId: JsonField) = apply { this.roleId = roleId } - /** The organization the ACL's referred object belongs to */ - fun _objectOrgId(_objectOrgId: String) = _objectOrgId(JsonField.of(_objectOrgId)) - - /** The organization the ACL's referred object belongs to */ - @JsonProperty("_object_org_id") - @ExcludeMissing - fun _objectOrgId(_objectOrgId: JsonField) = apply { - this._objectOrgId = _objectOrgId - } - - /** Date of acl creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) - /** Date of acl creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Acl]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ._objectOrgId() + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Acl = Acl( - id, - objectType, - objectId, - userId, + checkRequired("id", id), + checkRequired("_objectOrgId", _objectOrgId), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + created, groupId, permission, restrictObjectType, roleId, - _objectOrgId, - created, - additionalProperties.toUnmodifiable(), + userId, + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val EXPERIMENT = ObjectType(JsonField.of("experiment")) - - val DATASET = ObjectType(JsonField.of("dataset")) - - val PROMPT = ObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) - - val GROUP = ObjectType(JsonField.of("group")) - - val ROLE = ObjectType(JsonField.of("role")) - - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) - - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) - - fun of(value: String) = ObjectType(JsonField.of(value)) - } - - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + private var validated: Boolean = false - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, + fun validate(): Acl = apply { + if (validated) { + return@apply } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() + id() + _objectOrgId() + objectId() + objectType().validate() + created() + groupId() + permission()?.validate() + restrictObjectType()?.validate() + roleId() + userId() + validated = true } - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Permission && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) - - fun of(value: String) = Permission(JsonField.of(value)) - } - - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_objectOrgId.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (created.asKnown() == null) 0 else 1) + + (if (groupId.asKnown() == null) 0 else 1) + + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) + + (if (roleId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() + return other is Acl && + id == other.id && + _objectOrgId == other._objectOrgId && + objectId == other.objectId && + objectType == other.objectType && + created == other.created && + groupId == other.groupId && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + roleId == other.roleId && + userId == other.userId && + additionalProperties == other.additionalProperties } - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RestrictObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) - - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) - - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) - - fun of(value: String) = RestrictObjectType(JsonField.of(value)) - } - - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + private val hashCode: Int by lazy { + Objects.hash( + id, + _objectOrgId, + objectId, + objectType, + created, + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties, + ) + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + override fun hashCode(): Int = hashCode - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "Acl{id=$id, _objectOrgId=$_objectOrgId, objectId=$objectId, objectType=$objectType, created=$created, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateParams.kt index b79d7a09..1a7d8b17 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateParams.kt @@ -2,251 +2,119 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Batch update acls. This operation is idempotent, so adding acls which already exist will have no + * effect, and removing acls which do not exist will have no effect. + */ class AclBatchUpdateParams -constructor( - private val addAcls: List?, - private val removeAcls: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun addAcls(): List? = addAcls - - fun removeAcls(): List? = removeAcls - - internal fun getBody(): AclBatchUpdateBody { - return AclBatchUpdateBody( - addAcls, - removeAcls, - additionalBodyProperties, - ) - } - - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = AclBatchUpdateBody.Builder::class) - @NoAutoDetect - class AclBatchUpdateBody - internal constructor( - private val addAcls: List?, - private val removeAcls: List?, - private val additionalProperties: Map, - ) { - - private var hashCode: Int = 0 - - /** - * An ACL grants a certain permission or role to a certain user or group on an object. - * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. - * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in - * the ACL, as part of a direct permission grant or as part of a role. - */ - @JsonProperty("add_acls") fun addAcls(): List? = addAcls - - /** - * An ACL grants a certain permission or role to a certain user or group on an object. - * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. - * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in - * the ACL, as part of a direct permission grant or as part of a role. - */ - @JsonProperty("remove_acls") fun removeAcls(): List? = removeAcls - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AclBatchUpdateBody && - this.addAcls == other.addAcls && - this.removeAcls == other.removeAcls && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - addAcls, - removeAcls, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "AclBatchUpdateBody{addAcls=$addAcls, removeAcls=$removeAcls, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - class Builder { - - private var addAcls: List? = null - private var removeAcls: List? = null - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(aclBatchUpdateBody: AclBatchUpdateBody) = apply { - this.addAcls = aclBatchUpdateBody.addAcls - this.removeAcls = aclBatchUpdateBody.removeAcls - additionalProperties(aclBatchUpdateBody.additionalProperties) - } - - /** - * An ACL grants a certain permission or role to a certain user or group on an object. - * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. - * - * To restrict a grant to a particular sub-object, you may specify - * `restrict_object_type` in the ACL, as part of a direct permission grant or as part of - * a role. - */ - @JsonProperty("add_acls") - fun addAcls(addAcls: List) = apply { this.addAcls = addAcls } - - /** - * An ACL grants a certain permission or role to a certain user or group on an object. - * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. - * - * To restrict a grant to a particular sub-object, you may specify - * `restrict_object_type` in the ACL, as part of a direct permission grant or as part of - * a role. - */ - @JsonProperty("remove_acls") - fun removeAcls(removeAcls: List) = apply { this.removeAcls = removeAcls } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): AclBatchUpdateBody = - AclBatchUpdateBody( - addAcls?.toUnmodifiable(), - removeAcls?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) - } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams + /** + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, dataset, + * etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the + * ACL, as part of a direct permission grant or as part of a role. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun addAcls(): List? = body.addAcls() - fun _additionalHeaders(): Map> = additionalHeaders + /** + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, dataset, + * etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the + * ACL, as part of a direct permission grant or as part of a role. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun removeAcls(): List? = body.removeAcls() - fun _additionalBodyProperties(): Map = additionalBodyProperties + /** + * Returns the raw JSON value of [addAcls]. + * + * Unlike [addAcls], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _addAcls(): JsonField> = body._addAcls() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [removeAcls]. + * + * Unlike [removeAcls], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _removeAcls(): JsonField> = body._removeAcls() - return other is AclBatchUpdateParams && - this.addAcls == other.addAcls && - this.removeAcls == other.removeAcls && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun _additionalBodyProperties(): Map = body._additionalProperties() - override fun hashCode(): Int { - return Objects.hash( - addAcls, - removeAcls, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "AclBatchUpdateParams{addAcls=$addAcls, removeAcls=$removeAcls, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): AclBatchUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AclBatchUpdateParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [AclBatchUpdateParams]. */ + class Builder internal constructor() { - private var addAcls: MutableList = mutableListOf() - private var removeAcls: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(aclBatchUpdateParams: AclBatchUpdateParams) = apply { - this.addAcls(aclBatchUpdateParams.addAcls ?: listOf()) - this.removeAcls(aclBatchUpdateParams.removeAcls ?: listOf()) - additionalQueryParams(aclBatchUpdateParams.additionalQueryParams) - additionalHeaders(aclBatchUpdateParams.additionalHeaders) - additionalBodyProperties(aclBatchUpdateParams.additionalBodyProperties) + body = aclBatchUpdateParams.body.toBuilder() + additionalHeaders = aclBatchUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = aclBatchUpdateParams.additionalQueryParams.toBuilder() } /** - * An ACL grants a certain permission or role to a certain user or group on an object. - * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. + * Sets the entire request body. * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in - * the ACL, as part of a direct permission grant or as part of a role. + * 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: + * - [addAcls] + * - [removeAcls] */ - fun addAcls(addAcls: List) = apply { - this.addAcls.clear() - this.addAcls.addAll(addAcls) - } + fun body(body: Body) = apply { this.body = body.toBuilder() } /** * An ACL grants a certain permission or role to a certain user or group on an object. @@ -258,22 +126,23 @@ constructor( * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in * the ACL, as part of a direct permission grant or as part of a role. */ - fun addAddAcl(addAcl: AddAcl) = apply { this.addAcls.add(addAcl) } + fun addAcls(addAcls: List?) = apply { body.addAcls(addAcls) } /** - * An ACL grants a certain permission or role to a certain user or group on an object. + * Sets [Builder.addAcls] to an arbitrary JSON value. * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. + * You should usually call [Builder.addAcls] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun addAcls(addAcls: JsonField>) = apply { body.addAcls(addAcls) } + + /** + * Adds a single [AddAcl] to [addAcls]. * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in - * the ACL, as part of a direct permission grant or as part of a role. + * @throws IllegalStateException if the field was previously set to a non-list. */ - fun removeAcls(removeAcls: List) = apply { - this.removeAcls.clear() - this.removeAcls.addAll(removeAcls) - } + fun addAddAcl(addAcl: AddAcl) = apply { body.addAddAcl(addAcl) } /** * An ACL grants a certain permission or role to a certain user or group on an object. @@ -285,585 +154,852 @@ constructor( * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in * the ACL, as part of a direct permission grant or as part of a role. */ - fun addRemoveAcl(removeAcl: RemoveAcl) = apply { this.removeAcls.add(removeAcl) } + fun removeAcls(removeAcls: List?) = apply { body.removeAcls(removeAcls) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + /** + * Sets [Builder.removeAcls] to an arbitrary JSON value. + * + * You should usually call [Builder.removeAcls] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun removeAcls(removeAcls: JsonField>) = apply { + body.removeAcls(removeAcls) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + /** + * Adds a single [RemoveAcl] to [removeAcls]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveAcl(removeAcl: RemoveAcl) = apply { body.addRemoveAcl(removeAcl) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + 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 removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } fun additionalHeaders(additionalHeaders: Map>) = apply { this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + 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.additionalBodyProperties.putAll(additionalBodyProperties) + 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 [AclBatchUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): AclBatchUpdateParams = AclBatchUpdateParams( - if (addAcls.size == 0) null else addAcls.toUnmodifiable(), - if (removeAcls.size == 0) null else removeAcls.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - /** - * An ACL grants a certain permission or role to a certain user or group on an object. - * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, dataset, - * etc. created within that project. - * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the - * ACL, as part of a direct permission grant or as part of a role. - */ - @JsonDeserialize(builder = AddAcl.Builder::class) - @NoAutoDetect - class AddAcl - private constructor( - private val objectType: ObjectType?, - private val objectId: String?, - private val userId: String?, - private val groupId: String?, - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val roleId: String?, - private val additionalProperties: Map, - ) { + fun _body(): Body = body - private var hashCode: Int = 0 + override fun _headers(): Headers = additionalHeaders - /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + override fun _queryParams(): QueryParams = additionalQueryParams - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val addAcls: JsonField>, + private val removeAcls: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("add_acls") + @ExcludeMissing + addAcls: JsonField> = JsonMissing.of(), + @JsonProperty("remove_acls") + @ExcludeMissing + removeAcls: JsonField> = JsonMissing.of(), + ) : this(addAcls, removeAcls, mutableMapOf()) /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, + * dataset, etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in + * the ACL, as part of a direct permission grant or as part of a role. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("user_id") fun userId(): String? = userId + fun addAcls(): List? = addAcls.getNullable("add_acls") /** - * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, + * dataset, etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in + * the ACL, as part of a direct permission grant or as part of a role. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("group_id") fun groupId(): String? = groupId + fun removeAcls(): List? = removeAcls.getNullable("remove_acls") /** - * Each permission permits a certain type of operation on an object in the system + * Returns the raw JSON value of [addAcls]. * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * Unlike [addAcls], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("permission") fun permission(): Permission? = permission - - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + @JsonProperty("add_acls") @ExcludeMissing fun _addAcls(): JsonField> = addAcls /** - * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * Returns the raw JSON value of [removeAcls]. + * + * Unlike [removeAcls], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("role_id") fun roleId(): String? = roleId - - @JsonAnyGetter + @JsonProperty("remove_acls") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _removeAcls(): JsonField> = removeAcls - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AddAcl && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.userId == other.userId && - this.groupId == other.groupId && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.roleId == other.roleId && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectType, - objectId, - userId, - groupId, - permission, - restrictObjectType, - roleId, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "AddAcl{objectType=$objectType, objectId=$objectId, userId=$userId, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [Body]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Body]. */ + class Builder internal constructor() { - private var objectType: ObjectType? = null - private var objectId: String? = null - private var userId: String? = null - private var groupId: String? = null - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null - private var roleId: String? = null + private var addAcls: JsonField>? = null + private var removeAcls: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(addAcl: AddAcl) = apply { - this.objectType = addAcl.objectType - this.objectId = addAcl.objectId - this.userId = addAcl.userId - this.groupId = addAcl.groupId - this.permission = addAcl.permission - this.restrictObjectType = addAcl.restrictObjectType - this.roleId = addAcl.roleId - additionalProperties(addAcl.additionalProperties) + internal fun from(body: Body) = apply { + addAcls = body.addAcls.map { it.toMutableList() } + removeAcls = body.removeAcls.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() } - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } - - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + /** + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, + * dataset, etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify + * `restrict_object_type` in the ACL, as part of a direct permission grant or as part of + * a role. + */ + fun addAcls(addAcls: List?) = addAcls(JsonField.ofNullable(addAcls)) /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * Sets [Builder.addAcls] to an arbitrary JSON value. + * + * You should usually call [Builder.addAcls] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("user_id") fun userId(userId: String) = apply { this.userId = userId } + fun addAcls(addAcls: JsonField>) = apply { + this.addAcls = addAcls.map { it.toMutableList() } + } /** - * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * Adds a single [AddAcl] to [addAcls]. + * + * @throws IllegalStateException if the field was previously set to a non-list. */ - @JsonProperty("group_id") - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun addAddAcl(addAcl: AddAcl) = apply { + addAcls = + (addAcls ?: JsonField.of(mutableListOf())).also { + checkKnown("addAcls", it).add(addAcl) + } + } /** - * Each permission permits a certain type of operation on an object in the system + * An ACL grants a certain permission or role to a certain user or group on an object. * - * Permissions can be assigned to to objects on an individual basis, or grouped into - * roles + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, + * dataset, etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify + * `restrict_object_type` in the ACL, as part of a direct permission grant or as part of + * a role. */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun removeAcls(removeAcls: List?) = + removeAcls(JsonField.ofNullable(removeAcls)) - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { - this.restrictObjectType = restrictObjectType + /** + * Sets [Builder.removeAcls] to an arbitrary JSON value. + * + * You should usually call [Builder.removeAcls] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun removeAcls(removeAcls: JsonField>) = apply { + this.removeAcls = removeAcls.map { it.toMutableList() } } /** - * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be - * provided + * Adds a single [RemoveAcl] to [removeAcls]. + * + * @throws IllegalStateException if the field was previously set to a non-list. */ - @JsonProperty("role_id") fun roleId(roleId: String) = apply { this.roleId = roleId } + fun addRemoveAcl(removeAcl: RemoveAcl) = apply { + removeAcls = + (removeAcls ?: JsonField.of(mutableListOf())).also { + checkKnown("removeAcls", it).add(removeAcl) + } + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): AddAcl = - AddAcl( - checkNotNull(objectType) { "`objectType` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - userId, - groupId, - permission, - restrictObjectType, - roleId, - additionalProperties.toUnmodifiable(), + 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( + (addAcls ?: JsonMissing.of()).map { it.toImmutable() }, + (removeAcls ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Body = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + addAcls()?.forEach { it.validate() } + removeAcls()?.forEach { it.validate() } + validated = true + } - return other is ObjectType && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (addAcls.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (removeAcls.asKnown()?.sumOf { it.validity().toInt() } ?: 0) - companion object { + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - val ORGANIZATION = ObjectType(JsonField.of("organization")) + return other is Body && + addAcls == other.addAcls && + removeAcls == other.removeAcls && + additionalProperties == other.additionalProperties + } - val PROJECT = ObjectType(JsonField.of("project")) + private val hashCode: Int by lazy { + Objects.hash(addAcls, removeAcls, additionalProperties) + } - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + override fun hashCode(): Int = hashCode - val DATASET = ObjectType(JsonField.of("dataset")) + override fun toString() = + "Body{addAcls=$addAcls, removeAcls=$removeAcls, additionalProperties=$additionalProperties}" + } - val PROMPT = ObjectType(JsonField.of("prompt")) + /** + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, dataset, + * etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the + * ACL, as part of a direct permission grant or as part of a role. + */ + class AddAcl + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val objectId: JsonField, + private val objectType: JsonField, + private val groupId: JsonField, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val roleId: JsonField, + private val userId: JsonField, + private val additionalProperties: MutableMap, + ) { - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + @JsonProperty("role_id") @ExcludeMissing roleId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( + objectId, + objectType, + groupId, + permission, + restrictObjectType, + roleId, + userId, + mutableMapOf(), + ) - val GROUP = ObjectType(JsonField.of("group")) + /** + * The id of the object the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - val ROLE = ObjectType(JsonField.of("role")) + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + /** + * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun groupId(): String? = groupId.getNullable("group_id") - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + /** + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun permission(): Permission? = permission.getNullable("permission") - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") - fun of(value: String) = ObjectType(JsonField.of(value)) - } + /** + * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun roleId(): String? = roleId.getNullable("role_id") - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") + @ExcludeMissing + fun _permission(): JsonField = permission - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - return other is Permission && this.value == other.value - } + /** + * Returns the raw JSON value of [roleId]. + * + * Unlike [roleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role_id") @ExcludeMissing fun _roleId(): JsonField = roleId - override fun hashCode() = value.hashCode() + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId - override fun toString() = value.toString() + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - companion object { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - val CREATE = Permission(JsonField.of("create")) + fun toBuilder() = Builder().from(this) - val READ = Permission(JsonField.of("read")) + companion object { - val UPDATE = Permission(JsonField.of("update")) + /** + * Returns a mutable builder for constructing an instance of [AddAcl]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() + } - val DELETE = Permission(JsonField.of("delete")) + /** A builder for [AddAcl]. */ + class Builder internal constructor() { - val CREATE_ACLS = Permission(JsonField.of("create_acls")) + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var groupId: JsonField = JsonMissing.of() + private var permission: JsonField = JsonMissing.of() + private var restrictObjectType: JsonField = JsonMissing.of() + private var roleId: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - val READ_ACLS = Permission(JsonField.of("read_acls")) + internal fun from(addAcl: AddAcl) = apply { + objectId = addAcl.objectId + objectType = addAcl.objectType + groupId = addAcl.groupId + permission = addAcl.permission + restrictObjectType = addAcl.restrictObjectType + roleId = addAcl.roleId + userId = addAcl.userId + additionalProperties = addAcl.additionalProperties.toMutableMap() + } - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) + /** The id of the object the ACL applies to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - fun of(value: String) = Permission(JsonField.of(value)) - } + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType } - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, - } + /** + * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } + /** + * Sets [Builder.groupId] to an arbitrary JSON value. + * + * You should usually call [Builder.groupId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + /** + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided + */ + fun permission(permission: Permission?) = permission(JsonField.ofNullable(permission)) - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * When setting a permission directly, optionally restricts the permission grant to just + * the specified object type. Cannot be set alongside a `role_id`. + */ + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) - return other is RestrictObjectType && this.value == other.value + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { + this.restrictObjectType = restrictObjectType } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be + * provided + */ + fun roleId(roleId: String?) = roleId(JsonField.ofNullable(roleId)) - companion object { + /** + * Sets [Builder.roleId] to an arbitrary JSON value. + * + * You should usually call [Builder.roleId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun roleId(roleId: JsonField) = apply { this.roleId = roleId } - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) - val PROJECT = RestrictObjectType(JsonField.of("project")) + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - val DATASET = RestrictObjectType(JsonField.of("dataset")) + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - val PROMPT = RestrictObjectType(JsonField.of("prompt")) + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - val GROUP = RestrictObjectType(JsonField.of("group")) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - val ROLE = RestrictObjectType(JsonField.of("role")) + /** + * Returns an immutable instance of [AddAcl]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AddAcl = + AddAcl( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties.toMutableMap(), + ) + } - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) + private var validated: Boolean = false - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) + fun validate(): AddAcl = apply { + if (validated) { + return@apply + } - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) + objectId() + objectType().validate() + groupId() + permission()?.validate() + restrictObjectType()?.validate() + roleId() + userId() + validated = true + } - fun of(value: String) = RestrictObjectType(JsonField.of(value)) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (groupId.asKnown() == null) 0 else 1) + + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) + + (if (roleId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> - throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() + return other is AddAcl && + objectId == other.objectId && + objectType == other.objectType && + groupId == other.groupId && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + roleId == other.roleId && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + objectId, + objectType, + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties, + ) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AddAcl{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalProperties=$additionalProperties}" } /** @@ -876,158 +1012,284 @@ constructor( * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the * ACL, as part of a direct permission grant or as part of a role. */ - @JsonDeserialize(builder = RemoveAcl.Builder::class) - @NoAutoDetect class RemoveAcl + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val objectType: ObjectType?, - private val objectId: String?, - private val userId: String?, - private val groupId: String?, - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val roleId: String?, - private val additionalProperties: Map, + private val objectId: JsonField, + private val objectType: JsonField, + private val groupId: JsonField, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val roleId: JsonField, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 - - /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + @JsonProperty("role_id") @ExcludeMissing roleId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( + objectId, + objectType, + groupId, + permission, + restrictObjectType, + roleId, + userId, + mutableMapOf(), + ) - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + /** + * The id of the object the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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("user_id") fun userId(): String? = userId + fun objectType(): AclObjectType = objectType.getRequired("object_type") /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("group_id") fun groupId(): String? = groupId + fun groupId(): String? = groupId.getNullable("group_id") /** - * Each permission permits a certain type of operation on an object in the system + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("permission") fun permission(): Permission? = permission + fun permission(): Permission? = permission.getNullable("permission") - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") /** * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("role_id") fun roleId(): String? = roleId + fun roleId(): String? = roleId.getNullable("role_id") - @JsonAnyGetter + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _objectType(): JsonField = objectType - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") + @ExcludeMissing + fun _permission(): JsonField = permission - return other is RemoveAcl && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.userId == other.userId && - this.groupId == other.groupId && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.roleId == other.roleId && - this.additionalProperties == other.additionalProperties - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectType, - objectId, - userId, - groupId, - permission, - restrictObjectType, - roleId, - additionalProperties, - ) - } - return hashCode + /** + * Returns the raw JSON value of [roleId]. + * + * Unlike [roleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role_id") @ExcludeMissing fun _roleId(): JsonField = roleId + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "RemoveAcl{objectType=$objectType, objectId=$objectId, userId=$userId, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [RemoveAcl]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RemoveAcl]. */ + class Builder internal constructor() { - private var objectType: ObjectType? = null - private var objectId: String? = null - private var userId: String? = null - private var groupId: String? = null - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null - private var roleId: String? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var groupId: JsonField = JsonMissing.of() + private var permission: JsonField = JsonMissing.of() + private var restrictObjectType: JsonField = JsonMissing.of() + private var roleId: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(removeAcl: RemoveAcl) = apply { - this.objectType = removeAcl.objectType - this.objectId = removeAcl.objectId - this.userId = removeAcl.userId - this.groupId = removeAcl.groupId - this.permission = removeAcl.permission - this.restrictObjectType = removeAcl.restrictObjectType - this.roleId = removeAcl.roleId - additionalProperties(removeAcl.additionalProperties) + objectId = removeAcl.objectId + objectType = removeAcl.objectType + groupId = removeAcl.groupId + permission = removeAcl.permission + restrictObjectType = removeAcl.restrictObjectType + roleId = removeAcl.roleId + userId = removeAcl.userId + additionalProperties = removeAcl.additionalProperties.toMutableMap() } - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("user_id") fun userId(userId: String) = apply { this.userId = userId } + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided */ - @JsonProperty("group_id") - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) /** - * Each permission permits a certain type of operation on an object in the system + * Sets [Builder.groupId] to an arbitrary JSON value. * - * Permissions can be assigned to to objects on an individual basis, or grouped into - * roles + * You should usually call [Builder.groupId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { + /** + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided + */ + fun permission(permission: Permission?) = permission(JsonField.ofNullable(permission)) + + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } + + /** + * When setting a permission directly, optionally restricts the permission grant to just + * the specified object type. Cannot be set alongside a `role_id`. + */ + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) + + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { this.restrictObjectType = restrictObjectType } @@ -1035,349 +1297,165 @@ constructor( * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be * provided */ - @JsonProperty("role_id") fun roleId(roleId: String) = apply { this.roleId = roleId } + fun roleId(roleId: String?) = roleId(JsonField.ofNullable(roleId)) + + /** + * Sets [Builder.roleId] to an arbitrary JSON value. + * + * You should usually call [Builder.roleId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun roleId(roleId: JsonField) = apply { this.roleId = roleId } + + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RemoveAcl]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RemoveAcl = RemoveAcl( - checkNotNull(objectType) { "`objectType` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - userId, + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), groupId, permission, restrictObjectType, roleId, - additionalProperties.toUnmodifiable(), + userId, + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val EXPERIMENT = ObjectType(JsonField.of("experiment")) - - val DATASET = ObjectType(JsonField.of("dataset")) - - val PROMPT = ObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) - - val GROUP = ObjectType(JsonField.of("group")) - - val ROLE = ObjectType(JsonField.of("role")) - - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) - - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + private var validated: Boolean = false - fun of(value: String) = ObjectType(JsonField.of(value)) + fun validate(): RemoveAcl = apply { + if (validated) { + return@apply } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } - - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() + objectId() + objectType().validate() + groupId() + permission()?.validate() + restrictObjectType()?.validate() + roleId() + userId() + validated = true } - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Permission && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) - - fun of(value: String) = Permission(JsonField.of(value)) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (groupId.asKnown() == null) 0 else 1) + + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) + + (if (roleId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() + return other is RemoveAcl && + objectId == other.objectId && + objectType == other.objectType && + groupId == other.groupId && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + roleId == other.roleId && + userId == other.userId && + additionalProperties == other.additionalProperties } - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RestrictObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) - - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) + private val hashCode: Int by lazy { + Objects.hash( + objectId, + objectType, + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties, + ) + } - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) + override fun hashCode(): Int = hashCode - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) + override fun toString() = + "RemoveAcl{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalProperties=$additionalProperties}" + } - fun of(value: String) = RestrictObjectType(JsonField.of(value)) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + return other is AclBatchUpdateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> - throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "AclBatchUpdateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponse.kt index 2dd71157..d50cfade 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponse.kt @@ -6,26 +6,34 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = AclBatchUpdateResponse.Builder::class) -@NoAutoDetect class AclBatchUpdateResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val addedAcls: JsonField>, private val removedAcls: JsonField>, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("added_acls") + @ExcludeMissing + addedAcls: JsonField> = JsonMissing.of(), + @JsonProperty("removed_acls") + @ExcludeMissing + removedAcls: JsonField> = JsonMissing.of(), + ) : this(addedAcls, removedAcls, mutableMapOf()) /** * An ACL grants a certain permission or role to a certain user or group on an object. @@ -36,6 +44,9 @@ private constructor( * * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the * ACL, as part of a direct permission grant or as part of a role. + * + * @throws BraintrustInvalidDataException 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 addedAcls(): List = addedAcls.getRequired("added_acls") @@ -48,88 +59,65 @@ private constructor( * * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the * ACL, as part of a direct permission grant or as part of a role. + * + * @throws BraintrustInvalidDataException 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 removedAcls(): List = removedAcls.getRequired("removed_acls") /** - * An ACL grants a certain permission or role to a certain user or group on an object. + * Returns the raw JSON value of [addedAcls]. * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, dataset, - * etc. created within that project. - * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the - * ACL, as part of a direct permission grant or as part of a role. + * Unlike [addedAcls], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("added_acls") @ExcludeMissing fun _addedAcls() = addedAcls + @JsonProperty("added_acls") @ExcludeMissing fun _addedAcls(): JsonField> = addedAcls /** - * An ACL grants a certain permission or role to a certain user or group on an object. + * Returns the raw JSON value of [removedAcls]. * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, dataset, - * etc. created within that project. - * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the - * ACL, as part of a direct permission grant or as part of a role. + * Unlike [removedAcls], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("removed_acls") @ExcludeMissing fun _removedAcls() = removedAcls - - @JsonAnyGetter + @JsonProperty("removed_acls") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): AclBatchUpdateResponse = apply { - if (!validated) { - addedAcls().forEach { it.validate() } - removedAcls().forEach { it.validate() } - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun _removedAcls(): JsonField> = removedAcls - return other is AclBatchUpdateResponse && - this.addedAcls == other.addedAcls && - this.removedAcls == other.removedAcls && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - addedAcls, - removedAcls, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "AclBatchUpdateResponse{addedAcls=$addedAcls, removedAcls=$removedAcls, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [AclBatchUpdateResponse]. + * + * The following fields are required: + * ```kotlin + * .addedAcls() + * .removedAcls() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [AclBatchUpdateResponse]. */ + class Builder internal constructor() { - private var addedAcls: JsonField> = JsonMissing.of() - private var removedAcls: JsonField> = JsonMissing.of() + private var addedAcls: JsonField>? = null + private var removedAcls: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(aclBatchUpdateResponse: AclBatchUpdateResponse) = apply { - this.addedAcls = aclBatchUpdateResponse.addedAcls - this.removedAcls = aclBatchUpdateResponse.removedAcls - additionalProperties(aclBatchUpdateResponse.additionalProperties) + addedAcls = aclBatchUpdateResponse.addedAcls.map { it.toMutableList() } + removedAcls = aclBatchUpdateResponse.removedAcls.map { it.toMutableList() } + additionalProperties = aclBatchUpdateResponse.additionalProperties.toMutableMap() } /** @@ -145,18 +133,27 @@ private constructor( fun addedAcls(addedAcls: List) = addedAcls(JsonField.of(addedAcls)) /** - * An ACL grants a certain permission or role to a certain user or group on an object. + * Sets [Builder.addedAcls] to an arbitrary JSON value. * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. + * You should usually call [Builder.addedAcls] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun addedAcls(addedAcls: JsonField>) = apply { + this.addedAcls = addedAcls.map { it.toMutableList() } + } + + /** + * Adds a single [Acl] to [addedAcls]. * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in - * the ACL, as part of a direct permission grant or as part of a role. + * @throws IllegalStateException if the field was previously set to a non-list. */ - @JsonProperty("added_acls") - @ExcludeMissing - fun addedAcls(addedAcls: JsonField>) = apply { this.addedAcls = addedAcls } + fun addAddedAcl(addedAcl: Acl) = apply { + addedAcls = + (addedAcls ?: JsonField.of(mutableListOf())).also { + checkKnown("addedAcls", it).add(addedAcl) + } + } /** * An ACL grants a certain permission or role to a certain user or group on an object. @@ -171,40 +168,112 @@ private constructor( fun removedAcls(removedAcls: List) = removedAcls(JsonField.of(removedAcls)) /** - * An ACL grants a certain permission or role to a certain user or group on an object. - * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, - * dataset, etc. created within that project. + * Sets [Builder.removedAcls] to an arbitrary JSON value. * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in - * the ACL, as part of a direct permission grant or as part of a role. + * You should usually call [Builder.removedAcls] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("removed_acls") - @ExcludeMissing fun removedAcls(removedAcls: JsonField>) = apply { - this.removedAcls = removedAcls + this.removedAcls = removedAcls.map { it.toMutableList() } + } + + /** + * Adds a single [Acl] to [removedAcls]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemovedAcl(removedAcl: Acl) = apply { + removedAcls = + (removedAcls ?: JsonField.of(mutableListOf())).also { + checkKnown("removedAcls", it).add(removedAcl) + } } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [AclBatchUpdateResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .addedAcls() + * .removedAcls() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): AclBatchUpdateResponse = AclBatchUpdateResponse( - addedAcls.map { it.toUnmodifiable() }, - removedAcls.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + checkRequired("addedAcls", addedAcls).map { it.toImmutable() }, + checkRequired("removedAcls", removedAcls).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): AclBatchUpdateResponse = apply { + if (validated) { + return@apply + } + + addedAcls().forEach { it.validate() } + removedAcls().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (addedAcls.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (removedAcls.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AclBatchUpdateResponse && + addedAcls == other.addedAcls && + removedAcls == other.removedAcls && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(addedAcls, removedAcls, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AclBatchUpdateResponse{addedAcls=$addedAcls, removedAcls=$removedAcls, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclCreateParams.kt index ab87030c..4fc0369c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclCreateParams.kt @@ -2,291 +2,467 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new acl. If there is an existing acl with the same contents as the one specified in the + * request, will return the existing acl unmodified + */ class AclCreateParams -constructor( - private val objectId: String, - private val objectType: ObjectType, - private val groupId: String?, - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val roleId: String?, - private val userId: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun objectId(): String = objectId + /** + * The id of the object the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() - fun objectType(): ObjectType = objectType + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = body.objectType() - fun groupId(): String? = groupId + /** + * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupId(): String? = body.groupId() - fun permission(): Permission? = permission + /** + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun permission(): Permission? = body.permission() - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = body.restrictObjectType() - fun roleId(): String? = roleId + /** + * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun roleId(): String? = body.roleId() - fun userId(): String? = userId + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = body.userId() - internal fun getBody(): AclCreateBody { - return AclCreateBody( - objectId, - objectType, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalBodyProperties, - ) - } + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() - internal fun getQueryParams(): Map> = additionalQueryParams + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() - internal fun getHeaders(): Map> = additionalHeaders + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _groupId(): JsonField = body._groupId() /** - * An ACL grants a certain permission or role to a certain user or group on an object. + * Returns the raw JSON value of [permission]. * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, dataset, - * etc. created within that project. + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _permission(): JsonField = body._permission() + + /** + * Returns the raw JSON value of [restrictObjectType]. * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the - * ACL, as part of a direct permission grant or as part of a role. + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonDeserialize(builder = AclCreateBody.Builder::class) - @NoAutoDetect - class AclCreateBody - internal constructor( - private val objectId: String?, - private val objectType: ObjectType?, - private val groupId: String?, - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val roleId: String?, - private val userId: String?, - private val additionalProperties: Map, - ) { + fun _restrictObjectType(): JsonField = body._restrictObjectType() + + /** + * Returns the raw JSON value of [roleId]. + * + * Unlike [roleId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _roleId(): JsonField = body._roleId() + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _userId(): JsonField = body._userId() - private var hashCode: Int = 0 + 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 [AclCreateParams]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [AclCreateParams]. */ + 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() + + internal fun from(aclCreateParams: AclCreateParams) = apply { + body = aclCreateParams.body.toBuilder() + additionalHeaders = aclCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = aclCreateParams.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: + * - [objectId] + * - [objectType] + * - [groupId] + * - [permission] + * - [restrictObjectType] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** The id of the object the ACL applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + fun objectId(objectId: String) = apply { body.objectId(objectId) } + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + fun objectType(objectType: AclObjectType) = apply { body.objectType(objectType) } + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided */ - @JsonProperty("group_id") fun groupId(): String? = groupId + fun groupId(groupId: String?) = apply { body.groupId(groupId) } /** - * Each permission permits a certain type of operation on an object in the system + * Sets [Builder.groupId] to an arbitrary JSON value. * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * You should usually call [Builder.groupId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("permission") fun permission(): Permission? = permission + fun groupId(groupId: JsonField) = apply { body.groupId(groupId) } - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided */ + fun permission(permission: Permission?) = apply { body.permission(permission) } + + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { body.permission(permission) } + + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + */ + fun restrictObjectType(restrictObjectType: AclObjectType?) = apply { + body.restrictObjectType(restrictObjectType) + } + + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed [AclObjectType] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { + body.restrictObjectType(restrictObjectType) + } /** * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided */ - @JsonProperty("role_id") fun roleId(): String? = roleId + fun roleId(roleId: String?) = apply { body.roleId(roleId) } + + /** + * Sets [Builder.roleId] to an arbitrary JSON value. + * + * You should usually call [Builder.roleId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun roleId(roleId: JsonField) = apply { body.roleId(roleId) } /** * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided */ - @JsonProperty("user_id") fun userId(): String? = userId + fun userId(userId: String?) = apply { body.userId(userId) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { body.userId(userId) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is AclCreateBody && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.groupId == other.groupId && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.roleId == other.roleId && - this.userId == other.userId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectId, - objectType, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "AclCreateBody{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var objectId: String? = null - private var objectType: ObjectType? = null - private var groupId: String? = null - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null - private var roleId: String? = null - private var userId: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(aclCreateBody: AclCreateBody) = apply { - this.objectId = aclCreateBody.objectId - this.objectType = aclCreateBody.objectType - this.groupId = aclCreateBody.groupId - this.permission = aclCreateBody.permission - this.restrictObjectType = aclCreateBody.restrictObjectType - this.roleId = aclCreateBody.roleId - this.userId = aclCreateBody.userId - additionalProperties(aclCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided - */ - @JsonProperty("group_id") - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * Each permission permits a certain type of operation on an object in the system - * - * Permissions can be assigned to to objects on an individual basis, or grouped into - * roles - */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { - this.restrictObjectType = restrictObjectType - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** - * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be - * provided - */ - @JsonProperty("role_id") fun roleId(roleId: String) = apply { this.roleId = roleId } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided - */ - @JsonProperty("user_id") fun userId(userId: String) = apply { this.userId = userId } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): AclCreateBody = - AclCreateBody( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is AclCreateParams && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.groupId == other.groupId && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.roleId == other.roleId && - this.userId == other.userId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [AclCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AclCreateParams = + AclCreateParams(body.build(), additionalHeaders.build(), additionalQueryParams.build()) } - override fun hashCode(): Int { - return Objects.hash( + fun _body(): Body = body + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + /** + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, dataset, + * etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the + * ACL, as part of a direct permission grant or as part of a role. + */ + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val objectId: JsonField, + private val objectType: JsonField, + private val groupId: JsonField, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val roleId: JsonField, + private val userId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + @JsonProperty("role_id") @ExcludeMissing roleId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( objectId, objectType, groupId, @@ -294,465 +470,412 @@ constructor( restrictObjectType, roleId, userId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - - override fun toString() = - "AclCreateParams{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) - - companion object { - - fun builder() = Builder() - } - @NoAutoDetect - class Builder { - - private var objectId: String? = null - private var objectType: ObjectType? = null - private var groupId: String? = null - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null - private var roleId: String? = null - private var userId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() - - internal fun from(aclCreateParams: AclCreateParams) = apply { - this.objectId = aclCreateParams.objectId - this.objectType = aclCreateParams.objectType - this.groupId = aclCreateParams.groupId - this.permission = aclCreateParams.permission - this.restrictObjectType = aclCreateParams.restrictObjectType - this.roleId = aclCreateParams.roleId - this.userId = aclCreateParams.userId - additionalQueryParams(aclCreateParams.additionalQueryParams) - additionalHeaders(aclCreateParams.additionalHeaders) - additionalBodyProperties(aclCreateParams.additionalBodyProperties) - } - - /** The id of the object the ACL applies to */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + /** + * The id of the object the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun groupId(): String? = groupId.getNullable("group_id") /** - * Each permission permits a certain type of operation on an object in the system + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun permission(permission: Permission) = apply { this.permission = permission } + fun permission(): Permission? = permission.getNullable("permission") - /** The object type that the ACL applies to */ - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { - this.restrictObjectType = restrictObjectType - } + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") /** * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun roleId(roleId: String) = apply { this.roleId = roleId } + fun roleId(): String? = roleId.getNullable("role_id") /** * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun userId(userId: String) = apply { this.userId = userId } + fun userId(): String? = userId.getNullable("user_id") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") + @ExcludeMissing + fun _permission(): JsonField = permission - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Returns the raw JSON value of [roleId]. + * + * Unlike [roleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role_id") @ExcludeMissing fun _roleId(): JsonField = roleId - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun toBuilder() = Builder().from(this) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + companion object { - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun build(): AclCreateParams = - AclCreateParams( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } - - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var groupId: JsonField = JsonMissing.of() + private var permission: JsonField = JsonMissing.of() + private var restrictObjectType: JsonField = JsonMissing.of() + private var roleId: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(body: Body) = apply { + objectId = body.objectId + objectType = body.objectType + groupId = body.groupId + permission = body.permission + restrictObjectType = body.restrictObjectType + roleId = body.roleId + userId = body.userId + additionalProperties = body.additionalProperties.toMutableMap() } - return other is ObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) + /** The id of the object the ACL applies to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - val PROJECT = ObjectType(JsonField.of("project")) + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) - val DATASET = ObjectType(JsonField.of("dataset")) + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - val PROMPT = ObjectType(JsonField.of("prompt")) + /** + * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + /** + * Sets [Builder.groupId] to an arbitrary JSON value. + * + * You should usually call [Builder.groupId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } - val GROUP = ObjectType(JsonField.of("group")) + /** + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided + */ + fun permission(permission: Permission?) = permission(JsonField.ofNullable(permission)) - val ROLE = ObjectType(JsonField.of("role")) + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + /** + * When setting a permission directly, optionally restricts the permission grant to just + * the specified object type. Cannot be set alongside a `role_id`. + */ + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { + this.restrictObjectType = restrictObjectType + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + /** + * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be + * provided + */ + fun roleId(roleId: String?) = roleId(JsonField.ofNullable(roleId)) - fun of(value: String) = ObjectType(JsonField.of(value)) - } + /** + * Sets [Builder.roleId] to an arbitrary JSON value. + * + * You should usually call [Builder.roleId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun roleId(roleId: JsonField) = apply { this.roleId = roleId } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) } - fun asString(): String = _value().asStringOrThrow() - } - - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) } - return other is Permission && this.value == other.value + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties.toMutableMap(), + ) } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + private var validated: Boolean = false - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) - - fun of(value: String) = Permission(JsonField.of(value)) - } - - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + fun validate(): Body = apply { + if (validated) { + return@apply + } - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + objectId() + objectType().validate() + groupId() + permission()?.validate() + restrictObjectType()?.validate() + roleId() + userId() + validated = true } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun asString(): String = _value().asStringOrThrow() - } - - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (groupId.asKnown() == null) 0 else 1) + + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) + + (if (roleId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is RestrictObjectType && this.value == other.value + return other is Body && + objectId == other.objectId && + objectType == other.objectType && + groupId == other.groupId && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + roleId == other.roleId && + userId == other.userId && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) - - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) - - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) - - fun of(value: String) = RestrictObjectType(JsonField.of(value)) + private val hashCode: Int by lazy { + Objects.hash( + objectId, + objectType, + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties, + ) } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + override fun hashCode(): Int = hashCode - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, + override fun toString() = + "Body{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + return other is AclCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "AclCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclDeleteParams.kt index fac04dc9..bc159aec 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete an acl object by its id */ class AclDeleteParams -constructor( - private val aclId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val aclId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun aclId(): String = aclId + /** Acl id */ + fun aclId(): String? = aclId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> aclId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): AclDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AclDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [AclDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var aclId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(aclDeleteParams: AclDeleteParams) = apply { + aclId = aclDeleteParams.aclId + additionalHeaders = aclDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = aclDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = aclDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Acl id */ + fun aclId(aclId: String?) = apply { this.aclId = aclId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is AclDeleteParams && - this.aclId == other.aclId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - aclId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "AclDeleteParams{aclId=$aclId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var aclId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(aclDeleteParams: AclDeleteParams) = apply { - this.aclId = aclDeleteParams.aclId - additionalQueryParams(aclDeleteParams.additionalQueryParams) - additionalHeaders(aclDeleteParams.additionalHeaders) - additionalBodyProperties(aclDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Acl id */ - fun aclId(aclId: String) = apply { this.aclId = aclId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [AclDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): AclDeleteParams = AclDeleteParams( - checkNotNull(aclId) { "`aclId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + aclId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> aclId ?: "" + 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 AclDeleteParams && + aclId == other.aclId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(aclId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "AclDeleteParams{aclId=$aclId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParams.kt index e82c72d9..362a1351 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParams.kt @@ -2,291 +2,468 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** Delete a single acl */ class AclFindAndDeleteParams -constructor( - private val objectId: String, - private val objectType: ObjectType, - private val groupId: String?, - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val roleId: String?, - private val userId: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun objectId(): String = objectId + /** + * The id of the object the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() - fun objectType(): ObjectType = objectType + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = body.objectType() - fun groupId(): String? = groupId + /** + * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun groupId(): String? = body.groupId() - fun permission(): Permission? = permission + /** + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun permission(): Permission? = body.permission() - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = body.restrictObjectType() - fun roleId(): String? = roleId + /** + * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun roleId(): String? = body.roleId() - fun userId(): String? = userId + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = body.userId() - internal fun getBody(): AclFindAndDeleteBody { - return AclFindAndDeleteBody( - objectId, - objectType, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalBodyProperties, - ) - } + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() - internal fun getQueryParams(): Map> = additionalQueryParams + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() - internal fun getHeaders(): Map> = additionalHeaders + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _groupId(): JsonField = body._groupId() /** - * An ACL grants a certain permission or role to a certain user or group on an object. + * Returns the raw JSON value of [permission]. * - * ACLs are inherited across the object hierarchy. So for example, if a user has read - * permissions on a project, they will also have read permissions on any experiment, dataset, - * etc. created within that project. + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _permission(): JsonField = body._permission() + + /** + * Returns the raw JSON value of [restrictObjectType]. * - * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the - * ACL, as part of a direct permission grant or as part of a role. + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonDeserialize(builder = AclFindAndDeleteBody.Builder::class) - @NoAutoDetect - class AclFindAndDeleteBody - internal constructor( - private val objectId: String?, - private val objectType: ObjectType?, - private val groupId: String?, - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val roleId: String?, - private val userId: String?, - private val additionalProperties: Map, - ) { + fun _restrictObjectType(): JsonField = body._restrictObjectType() + + /** + * Returns the raw JSON value of [roleId]. + * + * Unlike [roleId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _roleId(): JsonField = body._roleId() + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _userId(): JsonField = body._userId() + + fun _additionalBodyProperties(): Map = body._additionalProperties() - private var hashCode: Int = 0 + /** 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 [AclFindAndDeleteParams]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [AclFindAndDeleteParams]. */ + 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() + + internal fun from(aclFindAndDeleteParams: AclFindAndDeleteParams) = apply { + body = aclFindAndDeleteParams.body.toBuilder() + additionalHeaders = aclFindAndDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = aclFindAndDeleteParams.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: + * - [objectId] + * - [objectType] + * - [groupId] + * - [permission] + * - [restrictObjectType] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** The id of the object the ACL applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + fun objectId(objectId: String) = apply { body.objectId(objectId) } + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + fun objectType(objectType: AclObjectType) = apply { body.objectType(objectType) } + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided */ - @JsonProperty("group_id") fun groupId(): String? = groupId + fun groupId(groupId: String?) = apply { body.groupId(groupId) } /** - * Each permission permits a certain type of operation on an object in the system + * Sets [Builder.groupId] to an arbitrary JSON value. * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * You should usually call [Builder.groupId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("permission") fun permission(): Permission? = permission + fun groupId(groupId: JsonField) = apply { body.groupId(groupId) } - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided */ + fun permission(permission: Permission?) = apply { body.permission(permission) } + + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { body.permission(permission) } + + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + */ + fun restrictObjectType(restrictObjectType: AclObjectType?) = apply { + body.restrictObjectType(restrictObjectType) + } + + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed [AclObjectType] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { + body.restrictObjectType(restrictObjectType) + } /** * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided */ - @JsonProperty("role_id") fun roleId(): String? = roleId + fun roleId(roleId: String?) = apply { body.roleId(roleId) } + + /** + * Sets [Builder.roleId] to an arbitrary JSON value. + * + * You should usually call [Builder.roleId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun roleId(roleId: JsonField) = apply { body.roleId(roleId) } /** * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided */ - @JsonProperty("user_id") fun userId(): String? = userId + fun userId(userId: String?) = apply { body.userId(userId) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { body.userId(userId) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is AclFindAndDeleteBody && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.groupId == other.groupId && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.roleId == other.roleId && - this.userId == other.userId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectId, - objectType, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "AclFindAndDeleteBody{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var objectId: String? = null - private var objectType: ObjectType? = null - private var groupId: String? = null - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null - private var roleId: String? = null - private var userId: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(aclFindAndDeleteBody: AclFindAndDeleteBody) = apply { - this.objectId = aclFindAndDeleteBody.objectId - this.objectType = aclFindAndDeleteBody.objectType - this.groupId = aclFindAndDeleteBody.groupId - this.permission = aclFindAndDeleteBody.permission - this.restrictObjectType = aclFindAndDeleteBody.restrictObjectType - this.roleId = aclFindAndDeleteBody.roleId - this.userId = aclFindAndDeleteBody.userId - additionalProperties(aclFindAndDeleteBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** The id of the object the ACL applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided - */ - @JsonProperty("group_id") - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * Each permission permits a certain type of operation on an object in the system - * - * Permissions can be assigned to to objects on an individual basis, or grouped into - * roles - */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { - this.restrictObjectType = restrictObjectType - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** - * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be - * provided - */ - @JsonProperty("role_id") fun roleId(roleId: String) = apply { this.roleId = roleId } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** - * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be - * provided - */ - @JsonProperty("user_id") fun userId(userId: String) = apply { this.userId = userId } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): AclFindAndDeleteBody = - AclFindAndDeleteBody( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is AclFindAndDeleteParams && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.groupId == other.groupId && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.roleId == other.roleId && - this.userId == other.userId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [AclFindAndDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AclFindAndDeleteParams = + AclFindAndDeleteParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( + fun _body(): Body = body + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + /** + * An ACL grants a certain permission or role to a certain user or group on an object. + * + * ACLs are inherited across the object hierarchy. So for example, if a user has read + * permissions on a project, they will also have read permissions on any experiment, dataset, + * etc. created within that project. + * + * To restrict a grant to a particular sub-object, you may specify `restrict_object_type` in the + * ACL, as part of a direct permission grant or as part of a role. + */ + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val objectId: JsonField, + private val objectType: JsonField, + private val groupId: JsonField, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val roleId: JsonField, + private val userId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + @JsonProperty("role_id") @ExcludeMissing roleId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( objectId, objectType, groupId, @@ -294,465 +471,412 @@ constructor( restrictObjectType, roleId, userId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - override fun toString() = - "AclFindAndDeleteParams{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) - - companion object { - - fun builder() = Builder() - } - - @NoAutoDetect - class Builder { - - private var objectId: String? = null - private var objectType: ObjectType? = null - private var groupId: String? = null - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null - private var roleId: String? = null - private var userId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() - - internal fun from(aclFindAndDeleteParams: AclFindAndDeleteParams) = apply { - this.objectId = aclFindAndDeleteParams.objectId - this.objectType = aclFindAndDeleteParams.objectType - this.groupId = aclFindAndDeleteParams.groupId - this.permission = aclFindAndDeleteParams.permission - this.restrictObjectType = aclFindAndDeleteParams.restrictObjectType - this.roleId = aclFindAndDeleteParams.roleId - this.userId = aclFindAndDeleteParams.userId - additionalQueryParams(aclFindAndDeleteParams.additionalQueryParams) - additionalHeaders(aclFindAndDeleteParams.additionalHeaders) - additionalBodyProperties(aclFindAndDeleteParams.additionalBodyProperties) - } - - /** The id of the object the ACL applies to */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + /** + * The id of the object the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") /** * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun groupId(): String? = groupId.getNullable("group_id") /** - * Each permission permits a certain type of operation on an object in the system + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun permission(permission: Permission) = apply { this.permission = permission } + fun permission(): Permission? = permission.getNullable("permission") - /** The object type that the ACL applies to */ - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { - this.restrictObjectType = restrictObjectType - } + /** + * When setting a permission directly, optionally restricts the permission grant to just the + * specified object type. Cannot be set alongside a `role_id`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") /** * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun roleId(roleId: String) = apply { this.roleId = roleId } + fun roleId(): String? = roleId.getNullable("role_id") /** * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be * provided + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun userId(userId: String) = apply { this.userId = userId } + fun userId(): String? = userId.getNullable("user_id") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") + @ExcludeMissing + fun _permission(): JsonField = permission - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Returns the raw JSON value of [roleId]. + * + * Unlike [roleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role_id") @ExcludeMissing fun _roleId(): JsonField = roleId - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun toBuilder() = Builder().from(this) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + companion object { - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun build(): AclFindAndDeleteParams = - AclFindAndDeleteParams( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - groupId, - permission, - restrictObjectType, - roleId, - userId, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } - - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var groupId: JsonField = JsonMissing.of() + private var permission: JsonField = JsonMissing.of() + private var restrictObjectType: JsonField = JsonMissing.of() + private var roleId: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(body: Body) = apply { + objectId = body.objectId + objectType = body.objectType + groupId = body.groupId + permission = body.permission + restrictObjectType = body.restrictObjectType + roleId = body.roleId + userId = body.userId + additionalProperties = body.additionalProperties.toMutableMap() } - return other is ObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) + /** The id of the object the ACL applies to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - val PROJECT = ObjectType(JsonField.of("project")) + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) - val DATASET = ObjectType(JsonField.of("dataset")) + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - val PROMPT = ObjectType(JsonField.of("prompt")) + /** + * Id of the group the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + /** + * Sets [Builder.groupId] to an arbitrary JSON value. + * + * You should usually call [Builder.groupId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } - val GROUP = ObjectType(JsonField.of("group")) + /** + * Permission the ACL grants. Exactly one of `permission` and `role_id` will be provided + */ + fun permission(permission: Permission?) = permission(JsonField.ofNullable(permission)) - val ROLE = ObjectType(JsonField.of("role")) + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + /** + * When setting a permission directly, optionally restricts the permission grant to just + * the specified object type. Cannot be set alongside a `role_id`. + */ + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { + this.restrictObjectType = restrictObjectType + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + /** + * Id of the role the ACL grants. Exactly one of `permission` and `role_id` will be + * provided + */ + fun roleId(roleId: String?) = roleId(JsonField.ofNullable(roleId)) - fun of(value: String) = ObjectType(JsonField.of(value)) - } + /** + * Sets [Builder.roleId] to an arbitrary JSON value. + * + * You should usually call [Builder.roleId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun roleId(roleId: JsonField) = apply { this.roleId = roleId } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + /** + * Id of the user the ACL applies to. Exactly one of `user_id` and `group_id` will be + * provided + */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) } - fun asString(): String = _value().asStringOrThrow() - } - - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) } - return other is Permission && this.value == other.value + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties.toMutableMap(), + ) } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + private var validated: Boolean = false - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) - - fun of(value: String) = Permission(JsonField.of(value)) - } - - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + fun validate(): Body = apply { + if (validated) { + return@apply + } - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + objectId() + objectType().validate() + groupId() + permission()?.validate() + restrictObjectType()?.validate() + roleId() + userId() + validated = true } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (groupId.asKnown() == null) 0 else 1) + + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) + + (if (roleId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is RestrictObjectType && this.value == other.value + return other is Body && + objectId == other.objectId && + objectType == other.objectType && + groupId == other.groupId && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + roleId == other.roleId && + userId == other.userId && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) - - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) - - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) - - fun of(value: String) = RestrictObjectType(JsonField.of(value)) + private val hashCode: Int by lazy { + Objects.hash( + objectId, + objectType, + groupId, + permission, + restrictObjectType, + roleId, + userId, + additionalProperties, + ) } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + override fun hashCode(): Int = hashCode - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, + override fun toString() = + "Body{objectId=$objectId, objectType=$objectType, groupId=$groupId, permission=$permission, restrictObjectType=$restrictObjectType, roleId=$roleId, userId=$userId, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + return other is AclFindAndDeleteParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "AclFindAndDeleteParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPage.kt index 65c9e320..4a72a69a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPage.kt @@ -2,172 +2,120 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.AclService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see AclService.list */ class AclListPage private constructor( - private val aclsService: AclService, + private val service: AclService, private val params: AclListParams, - private val response: Response, -) { + private val response: AclListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [AclListPageResponse], but gracefully handles missing data. + * + * @see AclListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AclListPage && - this.aclsService == other.aclsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - aclsService, - params, - response, - ) - } - - override fun toString() = - "AclListPage{aclsService=$aclsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPageParams(): AclListParams? { - if (!hasNextPage()) { - return null - } - - return if (params.endingBefore() != null) { - AclListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): AclListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - AclListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): AclListPage? { - return getNextPageParams()?.let { aclsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(aclsService: AclService, params: AclListParams, response: Response) = - AclListPage( - aclsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): AclListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): AclListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): AclListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [AclListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [AclListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: AclService? = null + private var params: AclListParams? = null + private var response: AclListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(aclListPage: AclListPage) = apply { + service = aclListPage.service + params = aclListPage.params + response = aclListPage.response } - override fun toString() = - "AclListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: AclService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: AclListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: AclListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [AclListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AclListPage = + AclListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is AclListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: AclListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = "AclListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPageAsync.kt index 3306ecd7..29c99610 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPageAsync.kt @@ -2,174 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.AclServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see AclServiceAsync.list */ class AclListPageAsync private constructor( - private val aclsService: AclServiceAsync, + private val service: AclServiceAsync, private val params: AclListParams, - private val response: Response, -) { + private val response: AclListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [AclListPageResponse], but gracefully handles missing data. + * + * @see AclListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AclListPageAsync && - this.aclsService == other.aclsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - aclsService, - params, - response, - ) - } - - override fun toString() = - "AclListPageAsync{aclsService=$aclsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): AclListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - AclListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): AclListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - AclListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): AclListPageAsync? { - return getNextPageParams()?.let { aclsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(aclsService: AclServiceAsync, params: AclListParams, response: Response) = - AclListPageAsync( - aclsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): AclListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): AclListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): AclListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [AclListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [AclListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: AclServiceAsync? = null + private var params: AclListParams? = null + private var response: AclListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(aclListPageAsync: AclListPageAsync) = apply { + service = aclListPageAsync.service + params = aclListPageAsync.params + response = aclListPageAsync.response } - override fun toString() = - "AclListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: AclServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: AclListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: AclListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [AclListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AclListPageAsync = + AclListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is AclListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: AclListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "AclListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPageResponse.kt new file mode 100644 index 00000000..31f5ee06 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListPageResponse.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 AclListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of acl objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [AclListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [AclListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(aclListPageResponse: AclListPageResponse) = apply { + objects = aclListPageResponse.objects.map { it.toMutableList() } + additionalProperties = aclListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of acl objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Acl] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Acl) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [AclListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AclListPageResponse = + AclListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AclListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AclListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AclListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListParams.kt index 01b9c277..7657de6d 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclListParams.kt @@ -2,135 +2,113 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -import com.fasterxml.jackson.annotation.JsonCreator -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all acls. The acls are sorted by creation date, with the most recently-created acls + * coming first + */ class AclListParams -constructor( +private constructor( private val objectId: String, - private val objectType: ObjectType, + private val objectType: AclObjectType, private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + /** The id of the object the ACL applies to */ fun objectId(): String = objectId - fun objectType(): ObjectType = objectType + /** The object type that the ACL applies to */ + fun objectType(): AclObjectType = objectType + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.objectId.let { params.put("object_id", listOf(it.toString())) } - this.objectType.let { params.put("object_type", listOf(it.toString())) } - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AclListParams && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - objectId, - objectType, - endingBefore, - ids, - limit, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "AclListParams{objectId=$objectId, objectType=$objectType, endingBefore=$endingBefore, ids=$ids, limit=$limit, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$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 [AclListParams]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [AclListParams]. */ + class Builder internal constructor() { private var objectId: String? = null - private var objectType: ObjectType? = null + private var objectType: AclObjectType? = null private var endingBefore: String? = null private var ids: Ids? = null private var limit: Long? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(aclListParams: AclListParams) = apply { - this.objectId = aclListParams.objectId - this.objectType = aclListParams.objectType - this.endingBefore = aclListParams.endingBefore - this.ids = aclListParams.ids - this.limit = aclListParams.limit - this.startingAfter = aclListParams.startingAfter - additionalQueryParams(aclListParams.additionalQueryParams) - additionalHeaders(aclListParams.additionalHeaders) + objectId = aclListParams.objectId + objectType = aclListParams.objectType + endingBefore = aclListParams.endingBefore + ids = aclListParams.ids + limit = aclListParams.limit + startingAfter = aclListParams.startingAfter + additionalHeaders = aclListParams.additionalHeaders.toBuilder() + additionalQueryParams = aclListParams.additionalQueryParams.toBuilder() } /** The id of the object the ACL applies to */ fun objectId(objectId: String) = apply { this.objectId = objectId } /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun objectType(objectType: AclObjectType) = apply { this.objectType = objectType } /** * Pagination cursor id. @@ -139,28 +117,29 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** * Pagination cursor id. @@ -169,183 +148,167 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } - - fun build(): AclListParams = - AclListParams( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - endingBefore, - ids, - limit, - startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) - } - - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ObjectType && this.value == other.value + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - override fun hashCode() = value.hashCode() + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val EXPERIMENT = ObjectType(JsonField.of("experiment")) - - val DATASET = ObjectType(JsonField.of("dataset")) - - val PROMPT = ObjectType(JsonField.of("prompt")) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - val GROUP = ObjectType(JsonField.of("group")) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - val ROLE = ObjectType(JsonField.of("role")) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun of(value: String) = ObjectType(JsonField.of(value)) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun asString(): String = _value().asStringOrThrow() + /** + * Returns an immutable instance of [AclListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AclListParams = + AclListParams( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + endingBefore, + ids, + limit, + startingAfter, + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + put("object_id", objectId) + put("object_type", objectType.toString()) + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -358,93 +321,74 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is AclListParams && + objectId == other.objectId && + objectType == other.objectType && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + objectId, + objectType, + endingBefore, + ids, + limit, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "AclListParams{objectId=$objectId, objectType=$objectType, endingBefore=$endingBefore, ids=$ids, limit=$limit, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclObjectType.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclObjectType.kt new file mode 100644 index 00000000..b1615e42 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclObjectType.kt @@ -0,0 +1,188 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Enum +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.errors.BraintrustInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator + +/** The object type that the ACL applies to */ +class AclObjectType @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 { + + val ORGANIZATION = of("organization") + + val PROJECT = of("project") + + val EXPERIMENT = of("experiment") + + val DATASET = of("dataset") + + val PROMPT = of("prompt") + + val PROMPT_SESSION = of("prompt_session") + + val GROUP = of("group") + + val ROLE = of("role") + + val ORG_MEMBER = of("org_member") + + val PROJECT_LOG = of("project_log") + + val ORG_PROJECT = of("org_project") + + fun of(value: String) = AclObjectType(JsonField.of(value)) + } + + /** An enum containing [AclObjectType]'s known values. */ + enum class Known { + ORGANIZATION, + PROJECT, + EXPERIMENT, + DATASET, + PROMPT, + PROMPT_SESSION, + GROUP, + ROLE, + ORG_MEMBER, + PROJECT_LOG, + ORG_PROJECT, + } + + /** + * An enum containing [AclObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [AclObjectType] 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 { + ORGANIZATION, + PROJECT, + EXPERIMENT, + DATASET, + PROMPT, + PROMPT_SESSION, + GROUP, + ROLE, + ORG_MEMBER, + PROJECT_LOG, + ORG_PROJECT, + /** + * An enum member indicating that [AclObjectType] 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) { + ORGANIZATION -> Value.ORGANIZATION + PROJECT -> Value.PROJECT + EXPERIMENT -> Value.EXPERIMENT + DATASET -> Value.DATASET + PROMPT -> Value.PROMPT + PROMPT_SESSION -> Value.PROMPT_SESSION + GROUP -> Value.GROUP + ROLE -> Value.ROLE + ORG_MEMBER -> Value.ORG_MEMBER + PROJECT_LOG -> Value.PROJECT_LOG + ORG_PROJECT -> Value.ORG_PROJECT + 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + ORGANIZATION -> Known.ORGANIZATION + PROJECT -> Known.PROJECT + EXPERIMENT -> Known.EXPERIMENT + DATASET -> Known.DATASET + PROMPT -> Known.PROMPT + PROMPT_SESSION -> Known.PROMPT_SESSION + GROUP -> Known.GROUP + ROLE -> Known.ROLE + ORG_MEMBER -> Known.ORG_MEMBER + PROJECT_LOG -> Known.PROJECT_LOG + ORG_PROJECT -> Known.ORG_PROJECT + else -> throw BraintrustInvalidDataException("Unknown AclObjectType: $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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): AclObjectType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + 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 AclObjectType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclRetrieveParams.kt index 86a4bf63..7dba6f78 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AclRetrieveParams.kt @@ -2,125 +2,184 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get an acl object by its id */ class AclRetrieveParams -constructor( - private val aclId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val aclId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun aclId(): String = aclId + /** Acl id */ + fun aclId(): String? = aclId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> aclId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): AclRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AclRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [AclRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var aclId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(aclRetrieveParams: AclRetrieveParams) = apply { + aclId = aclRetrieveParams.aclId + additionalHeaders = aclRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = aclRetrieveParams.additionalQueryParams.toBuilder() } - return other is AclRetrieveParams && - this.aclId == other.aclId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Acl id */ + fun aclId(aclId: String?) = apply { this.aclId = aclId } - override fun hashCode(): Int { - return Objects.hash( - aclId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "AclRetrieveParams{aclId=$aclId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var aclId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(aclRetrieveParams: AclRetrieveParams) = apply { - this.aclId = aclRetrieveParams.aclId - additionalQueryParams(aclRetrieveParams.additionalQueryParams) - additionalHeaders(aclRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Acl id */ - fun aclId(aclId: String) = apply { this.aclId = aclId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [AclRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): AclRetrieveParams = - AclRetrieveParams( - checkNotNull(aclId) { "`aclId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) + AclRetrieveParams(aclId, additionalHeaders.build(), additionalQueryParams.build()) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> aclId ?: "" + 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 AclRetrieveParams && + aclId == other.aclId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(aclId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "AclRetrieveParams{aclId=$aclId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecret.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecret.kt deleted file mode 100644 index 6931612a..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecret.kt +++ /dev/null @@ -1,301 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import java.time.OffsetDateTime -import java.util.Objects - -@JsonDeserialize(builder = AISecret.Builder::class) -@NoAutoDetect -class AISecret -private constructor( - private val id: JsonField, - private val created: JsonField, - private val orgId: JsonField, - private val name: JsonField, - private val type: JsonField, - private val metadata: JsonField, - private val previewSecret: JsonField, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the AI secret */ - fun id(): String = id.getRequired("id") - - /** Date of AI secret creation */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** Unique identifier for the organization */ - fun orgId(): String = orgId.getRequired("org_id") - - /** Name of the AI secret */ - fun name(): String = name.getRequired("name") - - fun type(): String? = type.getNullable("type") - - fun metadata(): Metadata? = metadata.getNullable("metadata") - - fun previewSecret(): String? = previewSecret.getNullable("preview_secret") - - /** Unique identifier for the AI secret */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Date of AI secret creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Unique identifier for the organization */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId - - /** Name of the AI secret */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - @JsonProperty("preview_secret") @ExcludeMissing fun _previewSecret() = previewSecret - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): AISecret = apply { - if (!validated) { - id() - created() - orgId() - name() - type() - metadata()?.validate() - previewSecret() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AISecret && - this.id == other.id && - this.created == other.created && - this.orgId == other.orgId && - this.name == other.name && - this.type == other.type && - this.metadata == other.metadata && - this.previewSecret == other.previewSecret && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - created, - orgId, - name, - type, - metadata, - previewSecret, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "AISecret{id=$id, created=$created, orgId=$orgId, name=$name, type=$type, metadata=$metadata, previewSecret=$previewSecret, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var id: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var orgId: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var previewSecret: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(aiSecret: AISecret) = apply { - this.id = aiSecret.id - this.created = aiSecret.created - this.orgId = aiSecret.orgId - this.name = aiSecret.name - this.type = aiSecret.type - this.metadata = aiSecret.metadata - this.previewSecret = aiSecret.previewSecret - additionalProperties(aiSecret.additionalProperties) - } - - /** Unique identifier for the AI secret */ - fun id(id: String) = id(JsonField.of(id)) - - /** Unique identifier for the AI secret */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** Date of AI secret creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** Date of AI secret creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - - /** Unique identifier for the organization */ - fun orgId(orgId: String) = orgId(JsonField.of(orgId)) - - /** Unique identifier for the organization */ - @JsonProperty("org_id") - @ExcludeMissing - fun orgId(orgId: JsonField) = apply { this.orgId = orgId } - - /** Name of the AI secret */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the AI secret */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - fun type(type: String) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - fun previewSecret(previewSecret: String) = previewSecret(JsonField.of(previewSecret)) - - @JsonProperty("preview_secret") - @ExcludeMissing - fun previewSecret(previewSecret: JsonField) = apply { - this.previewSecret = previewSecret - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): AISecret = - AISecret( - id, - created, - orgId, - name, - type, - metadata, - previewSecret, - additionalProperties.toUnmodifiable(), - ) - } - - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretCreateParams.kt index c6360608..111c3466 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretCreateParams.kt @@ -3,411 +3,778 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new ai_secret. If there is an existing ai_secret with the same name as the one specified + * in the request, will return the existing ai_secret unmodified + */ class AiSecretCreateParams -constructor( - private val name: String, - private val metadata: Metadata?, - private val orgName: String?, - private val secret: String?, - private val type: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun metadata(): Metadata? = metadata - - fun orgName(): String? = orgName - - fun secret(): String? = secret - - fun type(): String? = type - - internal fun getBody(): AiSecretCreateBody { - return AiSecretCreateBody( - name, - metadata, - orgName, - secret, - type, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * AI Secret belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Secret value. If omitted in a PUT request, the existing secret value will be left intact, not + * replaced with null. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun secret(): String? = body.secret() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): String? = body.type() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + /** + * Returns the raw JSON value of [secret]. + * + * Unlike [secret], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _secret(): JsonField = body._secret() + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _type(): JsonField = body._type() + + 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 [AiSecretCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [AiSecretCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = AiSecretCreateBody.Builder::class) - @NoAutoDetect - class AiSecretCreateBody - internal constructor( - private val name: String?, - private val metadata: Metadata?, - private val orgName: String?, - private val secret: String?, - private val type: String?, - private val additionalProperties: Map, - ) { + internal fun from(aiSecretCreateParams: AiSecretCreateParams) = apply { + body = aiSecretCreateParams.body.toBuilder() + additionalHeaders = aiSecretCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = aiSecretCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [metadata] + * - [orgName] + * - [secret] + * - [type] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the AI secret */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } - @JsonProperty("metadata") fun metadata(): Metadata? = metadata + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the AI Secret belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } /** * Secret value. If omitted in a PUT request, the existing secret value will be left intact, * not replaced with null. */ - @JsonProperty("secret") fun secret(): String? = secret + fun secret(secret: String?) = apply { body.secret(secret) } - @JsonProperty("type") fun type(): String? = type + /** + * Sets [Builder.secret] to an arbitrary JSON value. + * + * You should usually call [Builder.secret] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun secret(secret: JsonField) = apply { body.secret(secret) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun type(type: String?) = apply { body.type(type) } - fun toBuilder() = Builder().from(this) + /** + * 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 { body.type(type) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - return other is AiSecretCreateBody && - this.name == other.name && - this.metadata == other.metadata && - this.orgName == other.orgName && - this.secret == other.secret && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - metadata, - orgName, - secret, - type, - additionalProperties, - ) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "AiSecretCreateBody{name=$name, metadata=$metadata, orgName=$orgName, secret=$secret, type=$type, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var metadata: Metadata? = null - private var orgName: String? = null - private var secret: String? = null - private var type: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(aiSecretCreateBody: AiSecretCreateBody) = apply { - this.name = aiSecretCreateBody.name - this.metadata = aiSecretCreateBody.metadata - this.orgName = aiSecretCreateBody.orgName - this.secret = aiSecretCreateBody.secret - this.type = aiSecretCreateBody.type - additionalProperties(aiSecretCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the AI secret */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @JsonProperty("metadata") - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the AI Secret belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * Secret value. If omitted in a PUT request, the existing secret value will be left - * intact, not replaced with null. - */ - @JsonProperty("secret") fun secret(secret: String) = apply { this.secret = secret } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("type") fun type(type: String) = apply { this.type = type } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): AiSecretCreateBody = - AiSecretCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - metadata, - orgName, - secret, - type, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is AiSecretCreateParams && - this.name == other.name && - this.metadata == other.metadata && - this.orgName == other.orgName && - this.secret == other.secret && - this.type == other.type && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - name, - metadata, - orgName, - secret, - type, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "AiSecretCreateParams{name=$name, metadata=$metadata, orgName=$orgName, secret=$secret, type=$type, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [AiSecretCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AiSecretCreateParams = + AiSecretCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var metadata: Metadata? = null - private var orgName: String? = null - private var secret: String? = null - private var type: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(aiSecretCreateParams: AiSecretCreateParams) = apply { - this.name = aiSecretCreateParams.name - this.metadata = aiSecretCreateParams.metadata - this.orgName = aiSecretCreateParams.orgName - this.secret = aiSecretCreateParams.secret - this.type = aiSecretCreateParams.type - additionalQueryParams(aiSecretCreateParams.additionalQueryParams) - additionalHeaders(aiSecretCreateParams.additionalHeaders) - additionalBodyProperties(aiSecretCreateParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the AI secret */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val metadata: JsonField, + private val orgName: JsonField, + private val secret: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + @JsonProperty("secret") @ExcludeMissing secret: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, metadata, orgName, secret, type, mutableMapOf()) + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the AI Secret belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") /** * Secret value. If omitted in a PUT request, the existing secret value will be left intact, * not replaced with null. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun secret(secret: String) = apply { this.secret = secret } + fun secret(): String? = secret.getNullable("secret") - fun type(type: String) = apply { this.type = type } + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun type(): String? = type.getNullable("type") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * 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 - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [secret]. + * + * Unlike [secret], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("secret") @ExcludeMissing fun _secret(): JsonField = secret - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * 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 - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + private var name: JsonField? = null + private var metadata: JsonField = JsonMissing.of() + private var orgName: JsonField = JsonMissing.of() + private var secret: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) - } + internal fun from(body: Body) = apply { + name = body.name + metadata = body.metadata + orgName = body.orgName + secret = body.secret + type = body.type + additionalProperties = body.additionalProperties.toMutableMap() + } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Name of the AI secret */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the AI Secret belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + /** + * Secret value. If omitted in a PUT request, the existing secret value will be left + * intact, not replaced with null. + */ + fun secret(secret: String?) = secret(JsonField.ofNullable(secret)) + + /** + * Sets [Builder.secret] to an arbitrary JSON value. + * + * You should usually call [Builder.secret] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun secret(secret: JsonField) = apply { this.secret = secret } + + fun type(type: String?) = type(JsonField.ofNullable(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 additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } - fun build(): AiSecretCreateParams = - AiSecretCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - metadata, - orgName, - secret, - type, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - private var hashCode: Int = 0 + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun toBuilder() = Builder().from(this) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + metadata, + orgName, + secret, + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + metadata()?.validate() + orgName() + secret() + type() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (if (orgName.asKnown() == null) 0 else 1) + + (if (secret.asKnown() == null) 0 else 1) + + (if (type.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Metadata && this.additionalProperties == other.additionalProperties + return other is Body && + name == other.name && + metadata == other.metadata && + orgName == other.orgName && + secret == other.secret && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode + private val hashCode: Int by lazy { + Objects.hash(name, metadata, orgName, secret, type, additionalProperties) } - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, metadata=$metadata, orgName=$orgName, secret=$secret, type=$type, 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]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AiSecretCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "AiSecretCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretDeleteParams.kt index 56cf0fd0..152aad62 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete an ai_secret object by its id */ class AiSecretDeleteParams -constructor( - private val aiSecretId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val aiSecretId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun aiSecretId(): String = aiSecretId + /** AiSecret id */ + fun aiSecretId(): String? = aiSecretId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> aiSecretId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): AiSecretDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AiSecretDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [AiSecretDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var aiSecretId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(aiSecretDeleteParams: AiSecretDeleteParams) = apply { + aiSecretId = aiSecretDeleteParams.aiSecretId + additionalHeaders = aiSecretDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = aiSecretDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = aiSecretDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** AiSecret id */ + fun aiSecretId(aiSecretId: String?) = apply { this.aiSecretId = aiSecretId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is AiSecretDeleteParams && - this.aiSecretId == other.aiSecretId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - aiSecretId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "AiSecretDeleteParams{aiSecretId=$aiSecretId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var aiSecretId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(aiSecretDeleteParams: AiSecretDeleteParams) = apply { - this.aiSecretId = aiSecretDeleteParams.aiSecretId - additionalQueryParams(aiSecretDeleteParams.additionalQueryParams) - additionalHeaders(aiSecretDeleteParams.additionalHeaders) - additionalBodyProperties(aiSecretDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** AiSecret id */ - fun aiSecretId(aiSecretId: String) = apply { this.aiSecretId = aiSecretId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [AiSecretDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): AiSecretDeleteParams = AiSecretDeleteParams( - checkNotNull(aiSecretId) { "`aiSecretId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + aiSecretId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> aiSecretId ?: "" + 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 AiSecretDeleteParams && + aiSecretId == other.aiSecretId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(aiSecretId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "AiSecretDeleteParams{aiSecretId=$aiSecretId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParams.kt index 2476992c..6b581cf1 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParams.kt @@ -3,272 +3,484 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** Delete a single ai_secret */ class AiSecretFindAndDeleteParams -constructor( - private val name: String, - private val orgName: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun orgName(): String? = orgName - - internal fun getBody(): AiSecretFindAndDeleteBody { - return AiSecretFindAndDeleteBody( - name, - orgName, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * AI Secret belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + 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 [AiSecretFindAndDeleteParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [AiSecretFindAndDeleteParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = AiSecretFindAndDeleteBody.Builder::class) - @NoAutoDetect - class AiSecretFindAndDeleteBody - internal constructor( - private val name: String?, - private val orgName: String?, - private val additionalProperties: Map, - ) { + internal fun from(aiSecretFindAndDeleteParams: AiSecretFindAndDeleteParams) = apply { + body = aiSecretFindAndDeleteParams.body.toBuilder() + additionalHeaders = aiSecretFindAndDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = aiSecretFindAndDeleteParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [orgName] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the AI secret */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the AI Secret belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is AiSecretFindAndDeleteBody && - this.name == other.name && - this.orgName == other.orgName && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - orgName, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "AiSecretFindAndDeleteBody{name=$name, orgName=$orgName, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var name: String? = null - private var orgName: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(aiSecretFindAndDeleteBody: AiSecretFindAndDeleteBody) = apply { - this.name = aiSecretFindAndDeleteBody.name - this.orgName = aiSecretFindAndDeleteBody.orgName - additionalProperties(aiSecretFindAndDeleteBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the AI secret */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the AI Secret belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun build(): AiSecretFindAndDeleteBody = - AiSecretFindAndDeleteBody( - checkNotNull(name) { "`name` is required but was not set" }, - orgName, - additionalProperties.toUnmodifiable(), - ) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - return other is AiSecretFindAndDeleteParams && - this.name == other.name && - this.orgName == other.orgName && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun hashCode(): Int { - return Objects.hash( - name, - orgName, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - override fun toString() = - "AiSecretFindAndDeleteParams{name=$name, orgName=$orgName, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun toBuilder() = Builder().from(this) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - companion object { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun builder() = Builder() + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [AiSecretFindAndDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AiSecretFindAndDeleteParams = + AiSecretFindAndDeleteParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var orgName: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(aiSecretFindAndDeleteParams: AiSecretFindAndDeleteParams) = apply { - this.name = aiSecretFindAndDeleteParams.name - this.orgName = aiSecretFindAndDeleteParams.orgName - additionalQueryParams(aiSecretFindAndDeleteParams.additionalQueryParams) - additionalHeaders(aiSecretFindAndDeleteParams.additionalHeaders) - additionalBodyProperties(aiSecretFindAndDeleteParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the AI secret */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val orgName: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + ) : this(name, orgName, mutableMapOf()) + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the AI Secret belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun toBuilder() = Builder().from(this) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + companion object { - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + private var name: JsonField? = null + private var orgName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + internal fun from(body: Body) = apply { + name = body.name + orgName = body.orgName + additionalProperties = body.additionalProperties.toMutableMap() + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Name of the AI secret */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the AI Secret belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body(checkRequired("name", name), orgName, additionalProperties.toMutableMap()) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + orgName() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): AiSecretFindAndDeleteParams = - AiSecretFindAndDeleteParams( - checkNotNull(name) { "`name` is required but was not set" }, - orgName, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (if (orgName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + orgName == other.orgName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, orgName, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, orgName=$orgName, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AiSecretFindAndDeleteParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "AiSecretFindAndDeleteParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPage.kt index 3913033c..cbe84789 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPage.kt @@ -2,172 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.AiSecretService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see AiSecretService.list */ class AiSecretListPage private constructor( - private val aiSecretsService: AiSecretService, + private val service: AiSecretService, private val params: AiSecretListParams, - private val response: Response, -) { + private val response: AiSecretListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [AiSecretListPageResponse], but gracefully handles missing data. + * + * @see AiSecretListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AiSecretListPage && - this.aiSecretsService == other.aiSecretsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - aiSecretsService, - params, - response, - ) - } - - override fun toString() = - "AiSecretListPage{aiSecretsService=$aiSecretsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): AiSecretListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - AiSecretListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): AiSecretListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - AiSecretListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): AiSecretListPage? { - return getNextPageParams()?.let { aiSecretsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(aiSecretsService: AiSecretService, params: AiSecretListParams, response: Response) = - AiSecretListPage( - aiSecretsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): AiSecretListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): AiSecretListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): AiSecretListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [AiSecretListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [AiSecretListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: AiSecretService? = null + private var params: AiSecretListParams? = null + private var response: AiSecretListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(aiSecretListPage: AiSecretListPage) = apply { + service = aiSecretListPage.service + params = aiSecretListPage.params + response = aiSecretListPage.response } - override fun toString() = - "AiSecretListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: AiSecretService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: AiSecretListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: AiSecretListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [AiSecretListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AiSecretListPage = + AiSecretListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is AiSecretListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: AiSecretListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "AiSecretListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPageAsync.kt index 2faacd25..1dcd894f 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPageAsync.kt @@ -2,178 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.AiSecretServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see AiSecretServiceAsync.list */ class AiSecretListPageAsync private constructor( - private val aiSecretsService: AiSecretServiceAsync, + private val service: AiSecretServiceAsync, private val params: AiSecretListParams, - private val response: Response, -) { + private val response: AiSecretListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [AiSecretListPageResponse], but gracefully handles missing data. + * + * @see AiSecretListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AiSecretListPageAsync && - this.aiSecretsService == other.aiSecretsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - aiSecretsService, - params, - response, - ) - } - - override fun toString() = - "AiSecretListPageAsync{aiSecretsService=$aiSecretsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): AiSecretListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - AiSecretListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): AiSecretListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - AiSecretListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): AiSecretListPageAsync? { - return getNextPageParams()?.let { aiSecretsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - aiSecretsService: AiSecretServiceAsync, - params: AiSecretListParams, - response: Response - ) = - AiSecretListPageAsync( - aiSecretsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): AiSecretListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): AiSecretListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): AiSecretListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [AiSecretListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [AiSecretListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: AiSecretServiceAsync? = null + private var params: AiSecretListParams? = null + private var response: AiSecretListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(aiSecretListPageAsync: AiSecretListPageAsync) = apply { + service = aiSecretListPageAsync.service + params = aiSecretListPageAsync.params + response = aiSecretListPageAsync.response } - override fun toString() = - "AiSecretListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: AiSecretServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: AiSecretListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: AiSecretListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [AiSecretListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AiSecretListPageAsync = + AiSecretListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is AiSecretListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: AiSecretListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "AiSecretListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPageResponse.kt new file mode 100644 index 00000000..3797056d --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 AiSecretListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of ai_secret objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [AiSecretListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [AiSecretListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(aiSecretListPageResponse: AiSecretListPageResponse) = apply { + objects = aiSecretListPageResponse.objects.map { it.toMutableList() } + additionalProperties = aiSecretListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of ai_secret objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [AISecret] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: AISecret) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [AiSecretListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AiSecretListPageResponse = + AiSecretListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AiSecretListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AiSecretListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AiSecretListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListParams.kt index a5fb8ff9..686b85a0 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all ai_secrets. The ai_secrets are sorted by creation date, with the most + * recently-created ai_secrets coming first + */ class AiSecretListParams -constructor( +private constructor( private val aiSecretName: String?, private val aiSecretType: AiSecretType?, private val endingBefore: String?, @@ -28,86 +22,63 @@ constructor( private val limit: Long?, private val orgName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + /** Name of the ai_secret to search for */ fun aiSecretName(): String? = aiSecretName fun aiSecretType(): AiSecretType? = aiSecretType + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.aiSecretName?.let { params.put("ai_secret_name", listOf(it.toString())) } - this.aiSecretType?.let { params.put("ai_secret_type", listOf(it.toString())) } - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AiSecretListParams && - this.aiSecretName == other.aiSecretName && - this.aiSecretType == other.aiSecretType && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - aiSecretName, - aiSecretType, - endingBefore, - ids, - limit, - orgName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "AiSecretListParams{aiSecretName=$aiSecretName, aiSecretType=$aiSecretType, endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): AiSecretListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AiSecretListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [AiSecretListParams]. */ + class Builder internal constructor() { private var aiSecretName: String? = null private var aiSecretType: AiSecretType? = null @@ -116,33 +87,32 @@ constructor( private var limit: Long? = null private var orgName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(aiSecretListParams: AiSecretListParams) = apply { - this.aiSecretName = aiSecretListParams.aiSecretName - this.aiSecretType = aiSecretListParams.aiSecretType - this.endingBefore = aiSecretListParams.endingBefore - this.ids = aiSecretListParams.ids - this.limit = aiSecretListParams.limit - this.orgName = aiSecretListParams.orgName - this.startingAfter = aiSecretListParams.startingAfter - additionalQueryParams(aiSecretListParams.additionalQueryParams) - additionalHeaders(aiSecretListParams.additionalHeaders) + aiSecretName = aiSecretListParams.aiSecretName + aiSecretType = aiSecretListParams.aiSecretType + endingBefore = aiSecretListParams.endingBefore + ids = aiSecretListParams.ids + limit = aiSecretListParams.limit + orgName = aiSecretListParams.orgName + startingAfter = aiSecretListParams.startingAfter + additionalHeaders = aiSecretListParams.additionalHeaders.toBuilder() + additionalQueryParams = aiSecretListParams.additionalQueryParams.toBuilder() } /** Name of the ai_secret to search for */ - fun aiSecretName(aiSecretName: String) = apply { this.aiSecretName = aiSecretName } + fun aiSecretName(aiSecretName: String?) = apply { this.aiSecretName = aiSecretName } - fun aiSecretType(aiSecretType: AiSecretType) = apply { this.aiSecretType = aiSecretType } + fun aiSecretType(aiSecretType: AiSecretType?) = apply { this.aiSecretType = aiSecretType } - fun aiSecretType(string: String) = apply { - this.aiSecretType = AiSecretType.ofString(string) - } + /** Alias for calling [aiSecretType] with `AiSecretType.ofString(string)`. */ + fun aiSecretType(string: String) = aiSecretType(AiSecretType.ofString(string)) - fun aiSecretType(strings: List) = apply { - this.aiSecretType = AiSecretType.ofStrings(strings) - } + /** Alias for calling [aiSecretType] with `AiSecretType.ofStrings(strings)`. */ + fun aiSecretTypeOfStrings(strings: List) = + aiSecretType(AiSecretType.ofStrings(strings)) /** * Pagination cursor id. @@ -151,31 +121,32 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** * Pagination cursor id. @@ -184,48 +155,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [AiSecretListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): AiSecretListParams = AiSecretListParams( aiSecretName, @@ -235,22 +269,53 @@ constructor( limit, orgName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = AiSecretType.Deserializer::class) - @JsonSerialize(using = AiSecretType.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + aiSecretName?.let { put("ai_secret_name", it) } + aiSecretType?.accept( + object : AiSecretType.Visitor { + override fun visitString(string: String) { + put("ai_secret_type", string) + } + + override fun visitStrings(strings: List) { + put("ai_secret_type", strings.joinToString(",")) + } + } + ) + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + class AiSecretType private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -263,109 +328,59 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): AiSecretType = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown AiSecretType: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid AiSecretType") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is AiSecretType && - this.string == other.string && - this.strings == other.strings + return other is AiSecretType && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "AiSecretType{string=$string}" strings != null -> "AiSecretType{strings=$strings}" - _json != null -> "AiSecretType{_unknown=$_json}" else -> throw IllegalStateException("Invalid AiSecretType") } - } companion object { fun ofString(string: String) = AiSecretType(string = string) - fun ofStrings(strings: List) = AiSecretType(strings = strings) + fun ofStrings(strings: List) = AiSecretType(strings = strings.toImmutable()) } + /** + * An interface that defines how to map each variant of [AiSecretType] to a value of type + * [T]. + */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown AiSecretType: $json") - } - } - - class Deserializer : BaseDeserializer(AiSecretType::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): AiSecretType { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return AiSecretType(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return AiSecretType(strings = it, _json = json) - } - - return AiSecretType(_json = json) - } - } - - class Serializer : BaseSerializer(AiSecretType::class) { - - override fun serialize( - value: AiSecretType, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid AiSecretType") - } - } } } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -378,93 +393,76 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) + else -> throw IllegalStateException("Invalid Ids") } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true - } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is AiSecretListParams && + aiSecretName == other.aiSecretName && + aiSecretType == other.aiSecretType && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + aiSecretName, + aiSecretType, + endingBefore, + ids, + limit, + orgName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "AiSecretListParams{aiSecretName=$aiSecretName, aiSecretType=$aiSecretType, endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretReplaceParams.kt index 77dba57b..4b72ce8f 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretReplaceParams.kt @@ -3,411 +3,778 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create or replace ai_secret. If there is an existing ai_secret with the same name as the one + * specified in the request, will replace the existing ai_secret with the provided fields + */ class AiSecretReplaceParams -constructor( - private val name: String, - private val metadata: Metadata?, - private val orgName: String?, - private val secret: String?, - private val type: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun metadata(): Metadata? = metadata - - fun orgName(): String? = orgName - - fun secret(): String? = secret - - fun type(): String? = type - - internal fun getBody(): AiSecretReplaceBody { - return AiSecretReplaceBody( - name, - metadata, - orgName, - secret, - type, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * AI Secret belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Secret value. If omitted in a PUT request, the existing secret value will be left intact, not + * replaced with null. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun secret(): String? = body.secret() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): String? = body.type() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + /** + * Returns the raw JSON value of [secret]. + * + * Unlike [secret], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _secret(): JsonField = body._secret() + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _type(): JsonField = body._type() + + 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 [AiSecretReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [AiSecretReplaceParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = AiSecretReplaceBody.Builder::class) - @NoAutoDetect - class AiSecretReplaceBody - internal constructor( - private val name: String?, - private val metadata: Metadata?, - private val orgName: String?, - private val secret: String?, - private val type: String?, - private val additionalProperties: Map, - ) { + internal fun from(aiSecretReplaceParams: AiSecretReplaceParams) = apply { + body = aiSecretReplaceParams.body.toBuilder() + additionalHeaders = aiSecretReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = aiSecretReplaceParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [metadata] + * - [orgName] + * - [secret] + * - [type] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the AI secret */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } - @JsonProperty("metadata") fun metadata(): Metadata? = metadata + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the AI Secret belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } /** * Secret value. If omitted in a PUT request, the existing secret value will be left intact, * not replaced with null. */ - @JsonProperty("secret") fun secret(): String? = secret + fun secret(secret: String?) = apply { body.secret(secret) } - @JsonProperty("type") fun type(): String? = type + /** + * Sets [Builder.secret] to an arbitrary JSON value. + * + * You should usually call [Builder.secret] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun secret(secret: JsonField) = apply { body.secret(secret) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun type(type: String?) = apply { body.type(type) } - fun toBuilder() = Builder().from(this) + /** + * 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 { body.type(type) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - return other is AiSecretReplaceBody && - this.name == other.name && - this.metadata == other.metadata && - this.orgName == other.orgName && - this.secret == other.secret && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - metadata, - orgName, - secret, - type, - additionalProperties, - ) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "AiSecretReplaceBody{name=$name, metadata=$metadata, orgName=$orgName, secret=$secret, type=$type, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var metadata: Metadata? = null - private var orgName: String? = null - private var secret: String? = null - private var type: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(aiSecretReplaceBody: AiSecretReplaceBody) = apply { - this.name = aiSecretReplaceBody.name - this.metadata = aiSecretReplaceBody.metadata - this.orgName = aiSecretReplaceBody.orgName - this.secret = aiSecretReplaceBody.secret - this.type = aiSecretReplaceBody.type - additionalProperties(aiSecretReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the AI secret */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @JsonProperty("metadata") - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the AI Secret belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * Secret value. If omitted in a PUT request, the existing secret value will be left - * intact, not replaced with null. - */ - @JsonProperty("secret") fun secret(secret: String) = apply { this.secret = secret } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("type") fun type(type: String) = apply { this.type = type } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): AiSecretReplaceBody = - AiSecretReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - metadata, - orgName, - secret, - type, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is AiSecretReplaceParams && - this.name == other.name && - this.metadata == other.metadata && - this.orgName == other.orgName && - this.secret == other.secret && - this.type == other.type && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - name, - metadata, - orgName, - secret, - type, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "AiSecretReplaceParams{name=$name, metadata=$metadata, orgName=$orgName, secret=$secret, type=$type, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [AiSecretReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AiSecretReplaceParams = + AiSecretReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var metadata: Metadata? = null - private var orgName: String? = null - private var secret: String? = null - private var type: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(aiSecretReplaceParams: AiSecretReplaceParams) = apply { - this.name = aiSecretReplaceParams.name - this.metadata = aiSecretReplaceParams.metadata - this.orgName = aiSecretReplaceParams.orgName - this.secret = aiSecretReplaceParams.secret - this.type = aiSecretReplaceParams.type - additionalQueryParams(aiSecretReplaceParams.additionalQueryParams) - additionalHeaders(aiSecretReplaceParams.additionalHeaders) - additionalBodyProperties(aiSecretReplaceParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the AI secret */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val metadata: JsonField, + private val orgName: JsonField, + private val secret: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + @JsonProperty("secret") @ExcludeMissing secret: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, metadata, orgName, secret, type, mutableMapOf()) + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the AI Secret belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") /** * Secret value. If omitted in a PUT request, the existing secret value will be left intact, * not replaced with null. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun secret(secret: String) = apply { this.secret = secret } + fun secret(): String? = secret.getNullable("secret") - fun type(type: String) = apply { this.type = type } + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun type(): String? = type.getNullable("type") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * 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 - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [secret]. + * + * Unlike [secret], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("secret") @ExcludeMissing fun _secret(): JsonField = secret - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * 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 - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + private var name: JsonField? = null + private var metadata: JsonField = JsonMissing.of() + private var orgName: JsonField = JsonMissing.of() + private var secret: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) - } + internal fun from(body: Body) = apply { + name = body.name + metadata = body.metadata + orgName = body.orgName + secret = body.secret + type = body.type + additionalProperties = body.additionalProperties.toMutableMap() + } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Name of the AI secret */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the AI Secret belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + /** + * Secret value. If omitted in a PUT request, the existing secret value will be left + * intact, not replaced with null. + */ + fun secret(secret: String?) = secret(JsonField.ofNullable(secret)) + + /** + * Sets [Builder.secret] to an arbitrary JSON value. + * + * You should usually call [Builder.secret] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun secret(secret: JsonField) = apply { this.secret = secret } + + fun type(type: String?) = type(JsonField.ofNullable(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 additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } - fun build(): AiSecretReplaceParams = - AiSecretReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, - metadata, - orgName, - secret, - type, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - private var hashCode: Int = 0 + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun toBuilder() = Builder().from(this) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + metadata, + orgName, + secret, + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + metadata()?.validate() + orgName() + secret() + type() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (if (orgName.asKnown() == null) 0 else 1) + + (if (secret.asKnown() == null) 0 else 1) + + (if (type.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Metadata && this.additionalProperties == other.additionalProperties + return other is Body && + name == other.name && + metadata == other.metadata && + orgName == other.orgName && + secret == other.secret && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode + private val hashCode: Int by lazy { + Objects.hash(name, metadata, orgName, secret, type, additionalProperties) } - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, metadata=$metadata, orgName=$orgName, secret=$secret, type=$type, 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]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AiSecretReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "AiSecretReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParams.kt index 3ce06ad7..cb7f1e75 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParams.kt @@ -2,125 +2,189 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get an ai_secret object by its id */ class AiSecretRetrieveParams -constructor( - private val aiSecretId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val aiSecretId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun aiSecretId(): String = aiSecretId + /** AiSecret id */ + fun aiSecretId(): String? = aiSecretId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> aiSecretId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): AiSecretRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AiSecretRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [AiSecretRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var aiSecretId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(aiSecretRetrieveParams: AiSecretRetrieveParams) = apply { + aiSecretId = aiSecretRetrieveParams.aiSecretId + additionalHeaders = aiSecretRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = aiSecretRetrieveParams.additionalQueryParams.toBuilder() } - return other is AiSecretRetrieveParams && - this.aiSecretId == other.aiSecretId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** AiSecret id */ + fun aiSecretId(aiSecretId: String?) = apply { this.aiSecretId = aiSecretId } - override fun hashCode(): Int { - return Objects.hash( - aiSecretId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "AiSecretRetrieveParams{aiSecretId=$aiSecretId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var aiSecretId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(aiSecretRetrieveParams: AiSecretRetrieveParams) = apply { - this.aiSecretId = aiSecretRetrieveParams.aiSecretId - additionalQueryParams(aiSecretRetrieveParams.additionalQueryParams) - additionalHeaders(aiSecretRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** AiSecret id */ - fun aiSecretId(aiSecretId: String) = apply { this.aiSecretId = aiSecretId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [AiSecretRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): AiSecretRetrieveParams = AiSecretRetrieveParams( - checkNotNull(aiSecretId) { "`aiSecretId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + aiSecretId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> aiSecretId ?: "" + 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 AiSecretRetrieveParams && + aiSecretId == other.aiSecretId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(aiSecretId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "AiSecretRetrieveParams{aiSecretId=$aiSecretId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretUpdateParams.kt index 59aa2225..e948066a 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/AiSecretUpdateParams.kt @@ -3,380 +3,675 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update an ai_secret object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ class AiSecretUpdateParams -constructor( - private val aiSecretId: String, - private val metadata: Metadata?, - private val name: String?, - private val secret: String?, - private val type: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun aiSecretId(): String = aiSecretId - - fun metadata(): Metadata? = metadata - - fun name(): String? = name - - fun secret(): String? = secret - - fun type(): String? = type - - internal fun getBody(): AiSecretUpdateBody { - return AiSecretUpdateBody( - metadata, - name, - secret, - type, - additionalBodyProperties, - ) - } +private constructor( + private val aiSecretId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** AiSecret id */ + fun aiSecretId(): String? = aiSecretId + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun secret(): String? = body.secret() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): String? = body.type() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [secret]. + * + * Unlike [secret], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _secret(): JsonField = body._secret() + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _type(): JsonField = body._type() + + 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) - internal fun getQueryParams(): Map> = additionalQueryParams + companion object { - internal fun getHeaders(): Map> = additionalHeaders + fun none(): AiSecretUpdateParams = builder().build() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> aiSecretId - else -> "" - } + /** Returns a mutable builder for constructing an instance of [AiSecretUpdateParams]. */ + fun builder() = Builder() } - @JsonDeserialize(builder = AiSecretUpdateBody.Builder::class) - @NoAutoDetect - class AiSecretUpdateBody - internal constructor( - private val metadata: Metadata?, - private val name: String?, - private val secret: String?, - private val type: String?, - private val additionalProperties: Map, - ) { + /** A builder for [AiSecretUpdateParams]. */ + class Builder internal constructor() { + + private var aiSecretId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var hashCode: Int = 0 + internal fun from(aiSecretUpdateParams: AiSecretUpdateParams) = apply { + aiSecretId = aiSecretUpdateParams.aiSecretId + body = aiSecretUpdateParams.body.toBuilder() + additionalHeaders = aiSecretUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = aiSecretUpdateParams.additionalQueryParams.toBuilder() + } - @JsonProperty("metadata") fun metadata(): Metadata? = metadata + /** AiSecret id */ + fun aiSecretId(aiSecretId: String?) = apply { this.aiSecretId = aiSecretId } + + /** + * 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: + * - [metadata] + * - [name] + * - [secret] + * - [type] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } /** Name of the AI secret */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + fun secret(secret: String?) = apply { body.secret(secret) } + + /** + * Sets [Builder.secret] to an arbitrary JSON value. + * + * You should usually call [Builder.secret] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun secret(secret: JsonField) = apply { body.secret(secret) } + + fun type(type: String?) = apply { body.type(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 { body.type(type) } - @JsonProperty("secret") fun secret(): String? = secret + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - @JsonProperty("type") fun type(): String? = type + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } - return other is AiSecretUpdateBody && - this.metadata == other.metadata && - this.name == other.name && - this.secret == other.secret && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - metadata, - name, - secret, - type, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "AiSecretUpdateBody{metadata=$metadata, name=$name, secret=$secret, type=$type, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var metadata: Metadata? = null - private var name: String? = null - private var secret: String? = null - private var type: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(aiSecretUpdateBody: AiSecretUpdateBody) = apply { - this.metadata = aiSecretUpdateBody.metadata - this.name = aiSecretUpdateBody.name - this.secret = aiSecretUpdateBody.secret - this.type = aiSecretUpdateBody.type - additionalProperties(aiSecretUpdateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @JsonProperty("metadata") - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Name of the AI secret */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("secret") fun secret(secret: String) = apply { this.secret = secret } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - @JsonProperty("type") fun type(type: String) = apply { this.type = type } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): AiSecretUpdateBody = - AiSecretUpdateBody( - metadata, - name, - secret, - type, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is AiSecretUpdateParams && - this.aiSecretId == other.aiSecretId && - this.metadata == other.metadata && - this.name == other.name && - this.secret == other.secret && - this.type == other.type && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [AiSecretUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AiSecretUpdateParams = + AiSecretUpdateParams( + aiSecretId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - aiSecretId, - metadata, - name, - secret, - type, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "AiSecretUpdateParams{aiSecretId=$aiSecretId, metadata=$metadata, name=$name, secret=$secret, type=$type, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun _pathParam(index: Int): String = + when (index) { + 0 -> aiSecretId ?: "" + else -> "" + } - fun toBuilder() = Builder().from(this) + override fun _headers(): Headers = additionalHeaders - companion object { + override fun _queryParams(): QueryParams = additionalQueryParams - fun builder() = Builder() - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val metadata: JsonField, + private val name: JsonField, + private val secret: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { - @NoAutoDetect - class Builder { + @JsonCreator + private constructor( + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("secret") @ExcludeMissing secret: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(metadata, name, secret, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + + /** + * Name of the AI secret + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun secret(): String? = secret.getNullable("secret") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun type(): String? = type.getNullable("type") + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [secret]. + * + * Unlike [secret], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("secret") @ExcludeMissing fun _secret(): JsonField = secret + + /** + * 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) + } - private var aiSecretId: String? = null - private var metadata: Metadata? = null - private var name: String? = null - private var secret: String? = null - private var type: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - internal fun from(aiSecretUpdateParams: AiSecretUpdateParams) = apply { - this.aiSecretId = aiSecretUpdateParams.aiSecretId - this.metadata = aiSecretUpdateParams.metadata - this.name = aiSecretUpdateParams.name - this.secret = aiSecretUpdateParams.secret - this.type = aiSecretUpdateParams.type - additionalQueryParams(aiSecretUpdateParams.additionalQueryParams) - additionalHeaders(aiSecretUpdateParams.additionalHeaders) - additionalBodyProperties(aiSecretUpdateParams.additionalBodyProperties) + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - /** AiSecret id */ - fun aiSecretId(aiSecretId: String) = apply { this.aiSecretId = aiSecretId } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + private var metadata: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var secret: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** Name of the AI secret */ - fun name(name: String) = apply { this.name = name } + internal fun from(body: Body) = apply { + metadata = body.metadata + name = body.name + secret = body.secret + type = body.type + additionalProperties = body.additionalProperties.toMutableMap() + } - fun secret(secret: String) = apply { this.secret = secret } + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) - fun type(type: String) = apply { this.type = type } + /** + * 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 additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** Name of the AI secret */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun secret(secret: String?) = secret(JsonField.ofNullable(secret)) + + /** + * Sets [Builder.secret] to an arbitrary JSON value. + * + * You should usually call [Builder.secret] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun secret(secret: JsonField) = apply { this.secret = secret } + + fun type(type: String?) = type(JsonField.ofNullable(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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body(metadata, name, secret, type, additionalProperties.toMutableMap()) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + metadata()?.validate() + name() + secret() + type() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (metadata.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (if (secret.asKnown() == null) 0 else 1) + + (if (type.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + metadata == other.metadata && + name == other.name && + secret == other.secret && + type == other.type && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(metadata, name, secret, type, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): AiSecretUpdateParams = - AiSecretUpdateParams( - checkNotNull(aiSecretId) { "`aiSecretId` is required but was not set" }, - metadata, - name, - secret, - type, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{metadata=$metadata, name=$name, secret=$secret, type=$type, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is AiSecretUpdateParams && + aiSecretId == other.aiSecretId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(aiSecretId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "AiSecretUpdateParams{aiSecretId=$aiSecretId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKey.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKey.kt index 87aee8eb..e9b38dbe 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKey.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKey.kt @@ -6,210 +6,350 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ApiKey.Builder::class) -@NoAutoDetect class ApiKey +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val created: JsonField, private val name: JsonField, private val previewName: JsonField, - private val userId: JsonField, + private val created: JsonField, private val orgId: JsonField, - private val additionalProperties: Map, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the api key */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("preview_name") + @ExcludeMissing + previewName: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this(id, name, previewName, created, orgId, userId, mutableMapOf()) + + /** + * Unique identifier for the api key + * + * @throws BraintrustInvalidDataException 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") - /** Date of api key creation */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** Name of the api key */ + /** + * Name of the api key + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + /** + * @throws BraintrustInvalidDataException 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 previewName(): String = previewName.getRequired("preview_name") - /** Unique identifier for the user */ - fun userId(): String? = userId.getNullable("user_id") + /** + * Date of api key creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") - /** Unique identifier for the organization */ + /** + * Unique identifier for the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun orgId(): String? = orgId.getNullable("org_id") - /** Unique identifier for the api key */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Date of api key creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Name of the api key */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonProperty("preview_name") @ExcludeMissing fun _previewName() = previewName - - /** Unique identifier for the user */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + /** + * Unique identifier for the user + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - /** Unique identifier for the organization */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [previewName]. + * + * Unlike [previewName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("preview_name") + @ExcludeMissing + fun _previewName(): JsonField = previewName + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ApiKey = apply { - if (!validated) { - id() - created() - name() - previewName() - userId() - orgId() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ApiKey && - this.id == other.id && - this.created == other.created && - this.name == other.name && - this.previewName == other.previewName && - this.userId == other.userId && - this.orgId == other.orgId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - created, - name, - previewName, - userId, - orgId, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ApiKey{id=$id, created=$created, name=$name, previewName=$previewName, userId=$userId, orgId=$orgId, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ApiKey]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .previewName() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ApiKey]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var previewName: JsonField? = null private var created: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var previewName: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() private var orgId: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(apiKey: ApiKey) = apply { - this.id = apiKey.id - this.created = apiKey.created - this.name = apiKey.name - this.previewName = apiKey.previewName - this.userId = apiKey.userId - this.orgId = apiKey.orgId - additionalProperties(apiKey.additionalProperties) + id = apiKey.id + name = apiKey.name + previewName = apiKey.previewName + created = apiKey.created + orgId = apiKey.orgId + userId = apiKey.userId + additionalProperties = apiKey.additionalProperties.toMutableMap() } /** Unique identifier for the api key */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the api key */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** Date of api key creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** Date of api key creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } + /** + * 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 } /** Name of the api key */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the api key */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun previewName(previewName: String) = previewName(JsonField.of(previewName)) - @JsonProperty("preview_name") - @ExcludeMissing + /** + * Sets [Builder.previewName] to an arbitrary JSON value. + * + * You should usually call [Builder.previewName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun previewName(previewName: JsonField) = apply { this.previewName = previewName } - /** Unique identifier for the user */ - fun userId(userId: String) = userId(JsonField.of(userId)) - - /** Unique identifier for the user */ - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } - - /** Unique identifier for the organization */ - fun orgId(orgId: String) = orgId(JsonField.of(orgId)) + /** Date of api key creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } /** Unique identifier for the organization */ - @JsonProperty("org_id") - @ExcludeMissing + fun orgId(orgId: String?) = orgId(JsonField.ofNullable(orgId)) + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun orgId(orgId: JsonField) = apply { this.orgId = orgId } + /** Unique identifier for the user */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ApiKey]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .previewName() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ApiKey = ApiKey( - id, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("previewName", previewName), created, - name, - previewName, - userId, orgId, - additionalProperties.toUnmodifiable(), + userId, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): ApiKey = apply { + if (validated) { + return@apply + } + + id() + name() + previewName() + created() + orgId() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (previewName.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ApiKey && + id == other.id && + name == other.name && + previewName == other.previewName && + created == other.created && + orgId == other.orgId && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, name, previewName, created, orgId, userId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ApiKey{id=$id, name=$name, previewName=$previewName, created=$created, orgId=$orgId, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyCreateParams.kt index 14568b34..b11cee45 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyCreateParams.kt @@ -3,272 +3,487 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new api_key. It is possible to have multiple API keys with the same name. There is no + * de-duplication + */ class ApiKeyCreateParams -constructor( - private val name: String, - private val orgName: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun orgName(): String? = orgName - - internal fun getBody(): ApiKeyCreateBody { - return ApiKeyCreateBody( - name, - orgName, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the api key. Does not have to be unique + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * API key belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + 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 [ApiKeyCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ApiKeyCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = ApiKeyCreateBody.Builder::class) - @NoAutoDetect - class ApiKeyCreateBody - internal constructor( - private val name: String?, - private val orgName: String?, - private val additionalProperties: Map, - ) { + internal fun from(apiKeyCreateParams: ApiKeyCreateParams) = apply { + body = apiKeyCreateParams.body.toBuilder() + additionalHeaders = apiKeyCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = apiKeyCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [orgName] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the api key. Does not have to be unique */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the API key belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ApiKeyCreateBody && - this.name == other.name && - this.orgName == other.orgName && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - orgName, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "ApiKeyCreateBody{name=$name, orgName=$orgName, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var name: String? = null - private var orgName: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(apiKeyCreateBody: ApiKeyCreateBody) = apply { - this.name = apiKeyCreateBody.name - this.orgName = apiKeyCreateBody.orgName - additionalProperties(apiKeyCreateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the api key. Does not have to be unique */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the API key belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun build(): ApiKeyCreateBody = - ApiKeyCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - orgName, - additionalProperties.toUnmodifiable(), - ) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - return other is ApiKeyCreateParams && - this.name == other.name && - this.orgName == other.orgName && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun hashCode(): Int { - return Objects.hash( - name, - orgName, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - override fun toString() = - "ApiKeyCreateParams{name=$name, orgName=$orgName, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun toBuilder() = Builder().from(this) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - companion object { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun builder() = Builder() + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [ApiKeyCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ApiKeyCreateParams = + ApiKeyCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var orgName: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(apiKeyCreateParams: ApiKeyCreateParams) = apply { - this.name = apiKeyCreateParams.name - this.orgName = apiKeyCreateParams.orgName - additionalQueryParams(apiKeyCreateParams.additionalQueryParams) - additionalHeaders(apiKeyCreateParams.additionalHeaders) - additionalBodyProperties(apiKeyCreateParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the api key. Does not have to be unique */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val orgName: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + ) : this(name, orgName, mutableMapOf()) + + /** + * Name of the api key. Does not have to be unique + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the API key belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun toBuilder() = Builder().from(this) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + companion object { - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + private var name: JsonField? = null + private var orgName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + internal fun from(body: Body) = apply { + name = body.name + orgName = body.orgName + additionalProperties = body.additionalProperties.toMutableMap() + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Name of the api key. Does not have to be unique */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the API key belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body(checkRequired("name", name), orgName, additionalProperties.toMutableMap()) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + orgName() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ApiKeyCreateParams = - ApiKeyCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - orgName, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (if (orgName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + orgName == other.orgName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, orgName, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, orgName=$orgName, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ApiKeyCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ApiKeyCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParams.kt index 338b0aca..935a8bca 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete an api_key object by its id */ class ApiKeyDeleteParams -constructor( - private val apiKeyId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val apiKeyId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun apiKeyId(): String = apiKeyId + /** ApiKey id */ + fun apiKeyId(): String? = apiKeyId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> apiKeyId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ApiKeyDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ApiKeyDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ApiKeyDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var apiKeyId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(apiKeyDeleteParams: ApiKeyDeleteParams) = apply { + apiKeyId = apiKeyDeleteParams.apiKeyId + additionalHeaders = apiKeyDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = apiKeyDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = apiKeyDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** ApiKey id */ + fun apiKeyId(apiKeyId: String?) = apply { this.apiKeyId = apiKeyId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ApiKeyDeleteParams && - this.apiKeyId == other.apiKeyId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - apiKeyId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "ApiKeyDeleteParams{apiKeyId=$apiKeyId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var apiKeyId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(apiKeyDeleteParams: ApiKeyDeleteParams) = apply { - this.apiKeyId = apiKeyDeleteParams.apiKeyId - additionalQueryParams(apiKeyDeleteParams.additionalQueryParams) - additionalHeaders(apiKeyDeleteParams.additionalHeaders) - additionalBodyProperties(apiKeyDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** ApiKey id */ - fun apiKeyId(apiKeyId: String) = apply { this.apiKeyId = apiKeyId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [ApiKeyDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ApiKeyDeleteParams = ApiKeyDeleteParams( - checkNotNull(apiKeyId) { "`apiKeyId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + apiKeyId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> apiKeyId ?: "" + 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 ApiKeyDeleteParams && + apiKeyId == other.apiKeyId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(apiKeyId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "ApiKeyDeleteParams{apiKeyId=$apiKeyId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPage.kt index 6544fc5a..49bcf361 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPage.kt @@ -2,172 +2,120 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.ApiKeyService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see ApiKeyService.list */ class ApiKeyListPage private constructor( - private val apiKeysService: ApiKeyService, + private val service: ApiKeyService, private val params: ApiKeyListParams, - private val response: Response, -) { + private val response: ApiKeyListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [ApiKeyListPageResponse], but gracefully handles missing data. + * + * @see ApiKeyListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ApiKeyListPage && - this.apiKeysService == other.apiKeysService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - apiKeysService, - params, - response, - ) - } - - override fun toString() = - "ApiKeyListPage{apiKeysService=$apiKeysService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPageParams(): ApiKeyListParams? { - if (!hasNextPage()) { - return null - } - - return if (params.endingBefore() != null) { - ApiKeyListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ApiKeyListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ApiKeyListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): ApiKeyListPage? { - return getNextPageParams()?.let { apiKeysService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(apiKeysService: ApiKeyService, params: ApiKeyListParams, response: Response) = - ApiKeyListPage( - apiKeysService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): ApiKeyListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ApiKeyListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ApiKeyListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ApiKeyListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ApiKeyListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ApiKeyService? = null + private var params: ApiKeyListParams? = null + private var response: ApiKeyListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(apiKeyListPage: ApiKeyListPage) = apply { + service = apiKeyListPage.service + params = apiKeyListPage.params + response = apiKeyListPage.response } - override fun toString() = - "ApiKeyListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ApiKeyService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ApiKeyListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ApiKeyListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ApiKeyListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ApiKeyListPage = + ApiKeyListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ApiKeyListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ApiKeyListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = "ApiKeyListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPageAsync.kt index 8a6b6ce2..39fa0716 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPageAsync.kt @@ -2,174 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.ApiKeyServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see ApiKeyServiceAsync.list */ class ApiKeyListPageAsync private constructor( - private val apiKeysService: ApiKeyServiceAsync, + private val service: ApiKeyServiceAsync, private val params: ApiKeyListParams, - private val response: Response, -) { + private val response: ApiKeyListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [ApiKeyListPageResponse], but gracefully handles missing data. + * + * @see ApiKeyListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ApiKeyListPageAsync && - this.apiKeysService == other.apiKeysService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - apiKeysService, - params, - response, - ) - } - - override fun toString() = - "ApiKeyListPageAsync{apiKeysService=$apiKeysService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ApiKeyListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ApiKeyListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ApiKeyListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ApiKeyListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): ApiKeyListPageAsync? { - return getNextPageParams()?.let { apiKeysService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(apiKeysService: ApiKeyServiceAsync, params: ApiKeyListParams, response: Response) = - ApiKeyListPageAsync( - apiKeysService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): ApiKeyListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ApiKeyListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ApiKeyListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ApiKeyListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ApiKeyListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ApiKeyServiceAsync? = null + private var params: ApiKeyListParams? = null + private var response: ApiKeyListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(apiKeyListPageAsync: ApiKeyListPageAsync) = apply { + service = apiKeyListPageAsync.service + params = apiKeyListPageAsync.params + response = apiKeyListPageAsync.response } - override fun toString() = - "ApiKeyListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ApiKeyServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ApiKeyListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ApiKeyListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ApiKeyListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ApiKeyListPageAsync = + ApiKeyListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ApiKeyListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ApiKeyListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ApiKeyListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPageResponse.kt new file mode 100644 index 00000000..35352c05 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListPageResponse.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 ApiKeyListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of api_key objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [ApiKeyListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ApiKeyListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(apiKeyListPageResponse: ApiKeyListPageResponse) = apply { + objects = apiKeyListPageResponse.objects.map { it.toMutableList() } + additionalProperties = apiKeyListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of api_key objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [ApiKey] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: ApiKey) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [ApiKeyListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ApiKeyListPageResponse = + ApiKeyListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ApiKeyListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ApiKeyListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ApiKeyListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListParams.kt index be87baf4..5f92ac63 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyListParams.kt @@ -2,106 +2,80 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all api_keys. The api_keys are sorted by creation date, with the most recently-created + * api_keys coming first + */ class ApiKeyListParams -constructor( +private constructor( private val apiKeyName: String?, private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, private val orgName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + /** Name of the api_key to search for */ fun apiKeyName(): String? = apiKeyName + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.apiKeyName?.let { params.put("api_key_name", listOf(it.toString())) } - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ApiKeyListParams && - this.apiKeyName == other.apiKeyName && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - apiKeyName, - endingBefore, - ids, - limit, - orgName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "ApiKeyListParams{apiKeyName=$apiKeyName, endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ApiKeyListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ApiKeyListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ApiKeyListParams]. */ + class Builder internal constructor() { private var apiKeyName: String? = null private var endingBefore: String? = null @@ -109,22 +83,22 @@ constructor( private var limit: Long? = null private var orgName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(apiKeyListParams: ApiKeyListParams) = apply { - this.apiKeyName = apiKeyListParams.apiKeyName - this.endingBefore = apiKeyListParams.endingBefore - this.ids = apiKeyListParams.ids - this.limit = apiKeyListParams.limit - this.orgName = apiKeyListParams.orgName - this.startingAfter = apiKeyListParams.startingAfter - additionalQueryParams(apiKeyListParams.additionalQueryParams) - additionalHeaders(apiKeyListParams.additionalHeaders) + apiKeyName = apiKeyListParams.apiKeyName + endingBefore = apiKeyListParams.endingBefore + ids = apiKeyListParams.ids + limit = apiKeyListParams.limit + orgName = apiKeyListParams.orgName + startingAfter = apiKeyListParams.startingAfter + additionalHeaders = apiKeyListParams.additionalHeaders.toBuilder() + additionalQueryParams = apiKeyListParams.additionalQueryParams.toBuilder() } /** Name of the api_key to search for */ - fun apiKeyName(apiKeyName: String) = apply { this.apiKeyName = apiKeyName } + fun apiKeyName(apiKeyName: String?) = apply { this.apiKeyName = apiKeyName } /** * Pagination cursor id. @@ -133,31 +107,32 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** * Pagination cursor id. @@ -166,48 +141,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + 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 removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ApiKeyListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ApiKeyListParams = ApiKeyListParams( apiKeyName, @@ -216,22 +254,46 @@ constructor( limit, orgName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + apiKeyName?.let { put("api_key_name", it) } + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -244,93 +306,74 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) + else -> throw IllegalStateException("Invalid Ids") } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true - } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is ApiKeyListParams && + apiKeyName == other.apiKeyName && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + apiKeyName, + endingBefore, + ids, + limit, + orgName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ApiKeyListParams{apiKeyName=$apiKeyName, endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParams.kt index 8dcf6a7f..6b54b11b 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParams.kt @@ -2,125 +2,184 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get an api_key object by its id */ class ApiKeyRetrieveParams -constructor( - private val apiKeyId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val apiKeyId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun apiKeyId(): String = apiKeyId + /** ApiKey id */ + fun apiKeyId(): String? = apiKeyId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> apiKeyId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ApiKeyRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ApiKeyRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ApiKeyRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var apiKeyId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(apiKeyRetrieveParams: ApiKeyRetrieveParams) = apply { + apiKeyId = apiKeyRetrieveParams.apiKeyId + additionalHeaders = apiKeyRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = apiKeyRetrieveParams.additionalQueryParams.toBuilder() } - return other is ApiKeyRetrieveParams && - this.apiKeyId == other.apiKeyId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** ApiKey id */ + fun apiKeyId(apiKeyId: String?) = apply { this.apiKeyId = apiKeyId } - override fun hashCode(): Int { - return Objects.hash( - apiKeyId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "ApiKeyRetrieveParams{apiKeyId=$apiKeyId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var apiKeyId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(apiKeyRetrieveParams: ApiKeyRetrieveParams) = apply { - this.apiKeyId = apiKeyRetrieveParams.apiKeyId - additionalQueryParams(apiKeyRetrieveParams.additionalQueryParams) - additionalHeaders(apiKeyRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** ApiKey id */ - fun apiKeyId(apiKeyId: String) = apply { this.apiKeyId = apiKeyId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ApiKeyRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ApiKeyRetrieveParams = - ApiKeyRetrieveParams( - checkNotNull(apiKeyId) { "`apiKeyId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) + ApiKeyRetrieveParams(apiKeyId, additionalHeaders.build(), additionalQueryParams.build()) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> apiKeyId ?: "" + 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 ApiKeyRetrieveParams && + apiKeyId == other.apiKeyId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(apiKeyId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ApiKeyRetrieveParams{apiKeyId=$apiKeyId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImage.kt index fd41df79..01f9e5ca 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImage.kt @@ -7,284 +7,405 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ChatCompletionContentPartImage.Builder::class) -@NoAutoDetect class ChatCompletionContentPartImage +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val imageUrl: JsonField, private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("image_url") @ExcludeMissing imageUrl: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(imageUrl, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 imageUrl(): ImageUrl = imageUrl.getRequired("image_url") + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("image_url") @ExcludeMissing fun _imageUrl() = imageUrl - - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * Returns the raw JSON value of [imageUrl]. + * + * Unlike [imageUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("image_url") @ExcludeMissing fun _imageUrl(): JsonField = imageUrl + + /** + * 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 = additionalProperties - - fun validate(): ChatCompletionContentPartImage = apply { - if (!validated) { - imageUrl().validate() - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ChatCompletionContentPartImage && - this.imageUrl == other.imageUrl && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - imageUrl, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ChatCompletionContentPartImage{imageUrl=$imageUrl, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [ChatCompletionContentPartImage]. + * + * The following fields are required: + * ```kotlin + * .imageUrl() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ChatCompletionContentPartImage]. */ + class Builder internal constructor() { - private var imageUrl: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var imageUrl: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(chatCompletionContentPartImage: ChatCompletionContentPartImage) = apply { - this.imageUrl = chatCompletionContentPartImage.imageUrl - this.type = chatCompletionContentPartImage.type - additionalProperties(chatCompletionContentPartImage.additionalProperties) + imageUrl = chatCompletionContentPartImage.imageUrl + type = chatCompletionContentPartImage.type + additionalProperties = + chatCompletionContentPartImage.additionalProperties.toMutableMap() } fun imageUrl(imageUrl: ImageUrl) = imageUrl(JsonField.of(imageUrl)) - @JsonProperty("image_url") - @ExcludeMissing + /** + * Sets [Builder.imageUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.imageUrl] with a well-typed [ImageUrl] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun imageUrl(imageUrl: JsonField) = apply { this.imageUrl = imageUrl } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ChatCompletionContentPartImage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .imageUrl() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ChatCompletionContentPartImage = ChatCompletionContentPartImage( - imageUrl, - type, - additionalProperties.toUnmodifiable(), + checkRequired("imageUrl", imageUrl), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = ImageUrl.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): ChatCompletionContentPartImage = apply { + if (validated) { + return@apply + } + + imageUrl().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (imageUrl.asKnown()?.validity() ?: 0) + (type.asKnown()?.validity() ?: 0) + class ImageUrl + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val url: JsonField, private val detail: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("detail") @ExcludeMissing detail: JsonField = JsonMissing.of(), + ) : this(url, detail, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ fun detail(): Detail? = detail.getNullable("detail") - @JsonProperty("url") @ExcludeMissing fun _url() = url + /** + * 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 - @JsonProperty("detail") @ExcludeMissing fun _detail() = detail + /** + * Returns the raw JSON value of [detail]. + * + * Unlike [detail], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("detail") @ExcludeMissing fun _detail(): JsonField = detail + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ImageUrl = apply { - if (!validated) { - url() - detail() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ImageUrl && - this.url == other.url && - this.detail == other.detail && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - url, - detail, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ImageUrl{url=$url, detail=$detail, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ImageUrl]. + * + * The following fields are required: + * ```kotlin + * .url() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ImageUrl]. */ + class Builder internal constructor() { - private var url: JsonField = JsonMissing.of() + private var url: JsonField? = null private var detail: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(imageUrl: ImageUrl) = apply { - this.url = imageUrl.url - this.detail = imageUrl.detail - additionalProperties(imageUrl.additionalProperties) + url = imageUrl.url + detail = imageUrl.detail + additionalProperties = imageUrl.additionalProperties.toMutableMap() } fun url(url: String) = url(JsonField.of(url)) - @JsonProperty("url") - @ExcludeMissing + /** + * 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 detail(detail: Detail) = detail(JsonField.of(detail)) - @JsonProperty("detail") - @ExcludeMissing + /** + * Sets [Builder.detail] to an arbitrary JSON value. + * + * You should usually call [Builder.detail] with a well-typed [Detail] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun detail(detail: JsonField) = apply { this.detail = detail } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ImageUrl]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ImageUrl = - ImageUrl( - url, - detail, - additionalProperties.toUnmodifiable(), - ) + ImageUrl(checkRequired("url", url), detail, additionalProperties.toMutableMap()) } - class Detail - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): ImageUrl = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + url() + detail()?.validate() + validated = true + } - return other is Detail && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (url.asKnown() == null) 0 else 1) + (detail.asKnown()?.validity() ?: 0) + + class Detail @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 { - val AUTO = Detail(JsonField.of("auto")) + val AUTO = of("auto") - val LOW = Detail(JsonField.of("low")) + val LOW = of("low") - val HIGH = Detail(JsonField.of("high")) + val HIGH = of("high") fun of(value: String) = Detail(JsonField.of(value)) } + /** An enum containing [Detail]'s known values. */ enum class Known { AUTO, LOW, HIGH, } + /** + * An enum containing [Detail]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Detail] 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 { AUTO, LOW, HIGH, + /** + * An enum member indicating that [Detail] 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) { AUTO -> Value.AUTO @@ -293,6 +414,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { AUTO -> Known.AUTO @@ -301,58 +431,211 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown Detail: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Detail = apply { + if (validated) { + return@apply + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Detail && 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 Type && this.value == other.value + return other is ImageUrl && + url == other.url && + detail == other.detail && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { Objects.hash(url, detail, additionalProperties) } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "ImageUrl{url=$url, detail=$detail, additionalProperties=$additionalProperties}" + } + + 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 { - val IMAGE_URL = Type(JsonField.of("image_url")) + val IMAGE_URL = of("image_url") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - IMAGE_URL, + IMAGE_URL } + /** + * 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 { IMAGE_URL, + /** 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) { IMAGE_URL -> Value.IMAGE_URL 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { IMAGE_URL -> Known.IMAGE_URL else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ChatCompletionContentPartImage && + imageUrl == other.imageUrl && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(imageUrl, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ChatCompletionContentPartImage{imageUrl=$imageUrl, type=$type, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartText.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartText.kt index 70bfe04c..a8d25823 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartText.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartText.kt @@ -7,176 +7,315 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ChatCompletionContentPartText.Builder::class) -@NoAutoDetect class ChatCompletionContentPartText +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val text: JsonField, private val type: JsonField, - private val additionalProperties: Map, + private val text: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun text(): String? = text.getNullable("text") - + @JsonCreator + private constructor( + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + ) : this(type, text, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("text") @ExcludeMissing fun _text() = text + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun text(): String? = text.getNullable("text") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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 [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ChatCompletionContentPartText = apply { - if (!validated) { - text() - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ChatCompletionContentPartText && - this.text == other.text && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - text, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ChatCompletionContentPartText{text=$text, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [ChatCompletionContentPartText]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ChatCompletionContentPartText]. */ + class Builder internal constructor() { + private var type: JsonField? = null private var text: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(chatCompletionContentPartText: ChatCompletionContentPartText) = apply { - this.text = chatCompletionContentPartText.text - this.type = chatCompletionContentPartText.type - additionalProperties(chatCompletionContentPartText.additionalProperties) + type = chatCompletionContentPartText.type + text = chatCompletionContentPartText.text + additionalProperties = chatCompletionContentPartText.additionalProperties.toMutableMap() } - fun text(text: String) = text(JsonField.of(text)) - - @JsonProperty("text") - @ExcludeMissing - fun text(text: JsonField) = apply { this.text = text } - fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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 text(text: String) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun text(text: JsonField) = apply { this.text = text } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ChatCompletionContentPartText]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ChatCompletionContentPartText = ChatCompletionContentPartText( + checkRequired("type", type), text, - type, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): ChatCompletionContentPartText = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + type().validate() + text() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (type.asKnown()?.validity() ?: 0) + (if (text.asKnown() == null) 0 else 1) + + 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 { - val TEXT = Type(JsonField.of("text")) + val TEXT = of("text") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - TEXT, + TEXT } + /** + * 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 { TEXT, + /** 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) { TEXT -> Value.TEXT 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { TEXT -> Known.TEXT else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ChatCompletionContentPartText && + type == other.type && + text == other.text && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(type, text, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ChatCompletionContentPartText{type=$type, text=$text, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCall.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCall.kt index c4b44fad..fc6a4192 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCall.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCall.kt @@ -7,304 +7,543 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ChatCompletionMessageToolCall.Builder::class) -@NoAutoDetect class ChatCompletionMessageToolCall +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val function: JsonField, private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("function") @ExcludeMissing function: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(id, function, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 BraintrustInvalidDataException 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 function(): Function = function.getRequired("function") + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("id") @ExcludeMissing fun _id() = id - - @JsonProperty("function") @ExcludeMissing fun _function() = function - - @JsonProperty("type") @ExcludeMissing fun _type() = 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 [function]. + * + * Unlike [function], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("function") @ExcludeMissing fun _function(): JsonField = function + + /** + * 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 = additionalProperties - - fun validate(): ChatCompletionMessageToolCall = apply { - if (!validated) { - id() - function().validate() - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ChatCompletionMessageToolCall && - this.id == other.id && - this.function == other.function && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - function, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ChatCompletionMessageToolCall{id=$id, function=$function, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [ChatCompletionMessageToolCall]. + * + * The following fields are required: + * ```kotlin + * .id() + * .function() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ChatCompletionMessageToolCall]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var function: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var function: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(chatCompletionMessageToolCall: ChatCompletionMessageToolCall) = apply { - this.id = chatCompletionMessageToolCall.id - this.function = chatCompletionMessageToolCall.function - this.type = chatCompletionMessageToolCall.type - additionalProperties(chatCompletionMessageToolCall.additionalProperties) + id = chatCompletionMessageToolCall.id + function = chatCompletionMessageToolCall.function + type = chatCompletionMessageToolCall.type + additionalProperties = chatCompletionMessageToolCall.additionalProperties.toMutableMap() } fun id(id: String) = id(JsonField.of(id)) - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 function(function: Function) = function(JsonField.of(function)) - @JsonProperty("function") - @ExcludeMissing + /** + * Sets [Builder.function] to an arbitrary JSON value. + * + * You should usually call [Builder.function] with a well-typed [Function] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun function(function: JsonField) = apply { this.function = function } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ChatCompletionMessageToolCall]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .function() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ChatCompletionMessageToolCall = ChatCompletionMessageToolCall( - id, - function, - type, - additionalProperties.toUnmodifiable(), + checkRequired("id", id), + checkRequired("function", function), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): ChatCompletionMessageToolCall = apply { + if (validated) { + return@apply + } + + id() + function().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (function.asKnown()?.validity() ?: 0) + + (type.asKnown()?.validity() ?: 0) + class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val arguments: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("arguments") + @ExcludeMissing + arguments: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(arguments, name, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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(): String = arguments.getRequired("arguments") + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - @JsonProperty("arguments") @ExcludeMissing fun _arguments() = arguments + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - arguments() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Function && - this.arguments == other.arguments && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - arguments, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Function{arguments=$arguments, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Function]. + * + * The following fields are required: + * ```kotlin + * .arguments() + * .name() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Function]. */ + class Builder internal constructor() { - private var arguments: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var arguments: JsonField? = null + private var name: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(function: Function) = apply { - this.arguments = function.arguments - this.name = function.name - additionalProperties(function.additionalProperties) + arguments = function.arguments + name = function.name + additionalProperties = function.additionalProperties.toMutableMap() } fun arguments(arguments: String) = arguments(JsonField.of(arguments)) - @JsonProperty("arguments") - @ExcludeMissing + /** + * Sets [Builder.arguments] to an arbitrary JSON value. + * + * You should usually call [Builder.arguments] with a well-typed [String] 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 } fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .arguments() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Function = Function( - arguments, - name, - additionalProperties.toUnmodifiable(), + checkRequired("arguments", arguments), + checkRequired("name", name), + additionalProperties.toMutableMap(), ) } - } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Function = apply { + if (validated) { + return@apply + } + + arguments() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (arguments.asKnown() == null) 0 else 1) + (if (name.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Type && this.value == other.value + return other is Function && + arguments == other.arguments && + name == other.name && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { Objects.hash(arguments, name, additionalProperties) } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Function{arguments=$arguments, name=$name, additionalProperties=$additionalProperties}" + } + + 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 { - val FUNCTION = Type(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - FUNCTION, + FUNCTION } + /** + * 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 { FUNCTION, + /** 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) { FUNCTION -> Value.FUNCTION 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { FUNCTION -> Known.FUNCTION else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ChatCompletionMessageToolCall && + id == other.id && + function == other.function && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(id, function, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ChatCompletionMessageToolCall{id=$id, function=$function, type=$type, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CodeBundle.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CodeBundle.kt index 0f10c3d3..0476df19 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CodeBundle.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CodeBundle.kt @@ -9,9 +9,9 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -24,161 +24,257 @@ 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 -@JsonDeserialize(builder = CodeBundle.Builder::class) -@NoAutoDetect class CodeBundle +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val runtimeContext: JsonField, - private val location: JsonField, private val bundleId: JsonField, + private val location: JsonField, + private val runtimeContext: JsonField, private val preview: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun runtimeContext(): RuntimeContext = runtimeContext.getRequired("runtime_context") + @JsonCreator + private constructor( + @JsonProperty("bundle_id") @ExcludeMissing bundleId: JsonField = JsonMissing.of(), + @JsonProperty("location") @ExcludeMissing location: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("preview") @ExcludeMissing preview: JsonField = JsonMissing.of(), + ) : this(bundleId, location, runtimeContext, preview, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 bundleId(): String = bundleId.getRequired("bundle_id") + /** + * @throws BraintrustInvalidDataException 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 location(): Location = location.getRequired("location") - fun bundleId(): String = bundleId.getRequired("bundle_id") + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): RuntimeContext = runtimeContext.getRequired("runtime_context") - /** A preview of the code */ + /** + * A preview of the code + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun preview(): String? = preview.getNullable("preview") - @JsonProperty("runtime_context") @ExcludeMissing fun _runtimeContext() = runtimeContext - - @JsonProperty("location") @ExcludeMissing fun _location() = location - - @JsonProperty("bundle_id") @ExcludeMissing fun _bundleId() = bundleId - - /** A preview of the code */ - @JsonProperty("preview") @ExcludeMissing fun _preview() = preview + /** + * Returns the raw JSON value of [bundleId]. + * + * Unlike [bundleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("bundle_id") @ExcludeMissing fun _bundleId(): JsonField = bundleId + + /** + * 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 [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * Returns the raw JSON value of [preview]. + * + * Unlike [preview], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("preview") @ExcludeMissing fun _preview(): JsonField = preview + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): CodeBundle = apply { - if (!validated) { - runtimeContext().validate() - location() - bundleId() - preview() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is CodeBundle && - this.runtimeContext == other.runtimeContext && - this.location == other.location && - this.bundleId == other.bundleId && - this.preview == other.preview && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtimeContext, - location, - bundleId, - preview, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "CodeBundle{runtimeContext=$runtimeContext, location=$location, bundleId=$bundleId, preview=$preview, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [CodeBundle]. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [CodeBundle]. */ + class Builder internal constructor() { - private var runtimeContext: JsonField = JsonMissing.of() - private var location: JsonField = JsonMissing.of() - private var bundleId: JsonField = JsonMissing.of() + private var bundleId: JsonField? = null + private var location: JsonField? = null + private var runtimeContext: JsonField? = null private var preview: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(codeBundle: CodeBundle) = apply { - this.runtimeContext = codeBundle.runtimeContext - this.location = codeBundle.location - this.bundleId = codeBundle.bundleId - this.preview = codeBundle.preview - additionalProperties(codeBundle.additionalProperties) + bundleId = codeBundle.bundleId + location = codeBundle.location + runtimeContext = codeBundle.runtimeContext + preview = codeBundle.preview + additionalProperties = codeBundle.additionalProperties.toMutableMap() } - fun runtimeContext(runtimeContext: RuntimeContext) = - runtimeContext(JsonField.of(runtimeContext)) + fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - @JsonProperty("runtime_context") - @ExcludeMissing - fun runtimeContext(runtimeContext: JsonField) = apply { - this.runtimeContext = runtimeContext - } + /** + * Sets [Builder.bundleId] to an arbitrary JSON value. + * + * You should usually call [Builder.bundleId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun bundleId(bundleId: JsonField) = apply { this.bundleId = bundleId } fun location(location: Location) = location(JsonField.of(location)) - @JsonProperty("location") - @ExcludeMissing + /** + * Sets [Builder.location] to an arbitrary JSON value. + * + * You should usually call [Builder.location] with a well-typed [Location] 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 } - fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) + /** Alias for calling [location] with `Location.ofExperiment(experiment)`. */ + fun location(experiment: Location.Experiment) = location(Location.ofExperiment(experiment)) - @JsonProperty("bundle_id") - @ExcludeMissing - fun bundleId(bundleId: JsonField) = apply { this.bundleId = bundleId } + /** Alias for calling [location] with `Location.ofFunction(function)`. */ + fun location(function: Location.Function) = location(Location.ofFunction(function)) - /** A preview of the code */ - fun preview(preview: String) = preview(JsonField.of(preview)) + fun runtimeContext(runtimeContext: RuntimeContext) = + runtimeContext(JsonField.of(runtimeContext)) + + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed [RuntimeContext] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun runtimeContext(runtimeContext: JsonField) = apply { + this.runtimeContext = runtimeContext + } /** A preview of the code */ - @JsonProperty("preview") - @ExcludeMissing + fun preview(preview: String?) = preview(JsonField.ofNullable(preview)) + + /** + * Sets [Builder.preview] to an arbitrary JSON value. + * + * You should usually call [Builder.preview] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun preview(preview: JsonField) = apply { this.preview = preview } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [CodeBundle]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): CodeBundle = CodeBundle( - runtimeContext, - location, - bundleId, + checkRequired("bundleId", bundleId), + checkRequired("location", location), + checkRequired("runtimeContext", runtimeContext), preview, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): CodeBundle = apply { + if (validated) { + return@apply + } + + bundleId() + location().validate() + runtimeContext().validate() + preview() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (bundleId.asKnown() == null) 0 else 1) + + (location.asKnown()?.validity() ?: 0) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (if (preview.asKnown() == null) 0 else 1) + @JsonDeserialize(using = Location.Deserializer::class) @JsonSerialize(using = Location.Serializer::class) class Location @@ -188,8 +284,6 @@ private constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun experiment(): Experiment? = experiment fun function(): Function? = function @@ -204,47 +298,76 @@ private constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { experiment != null -> visitor.visitExperiment(experiment) function != null -> visitor.visitFunction(function) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Location = apply { - if (!validated) { - if (experiment == null && function == null) { - throw BraintrustInvalidDataException("Unknown Location: $_json") - } - experiment?.validate() - function?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitExperiment(experiment: Experiment) { + experiment.validate() + } + + override fun visitFunction(function: Function) { + function.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitExperiment(experiment: Experiment) = experiment.validity() + + override fun visitFunction(function: Function) = function.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Location && - this.experiment == other.experiment && - this.function == other.function + return other is Location && experiment == other.experiment && function == other.function } - override fun hashCode(): Int { - return Objects.hash(experiment, function) - } + override fun hashCode(): Int = Objects.hash(experiment, function) - override fun toString(): String { - return when { + override fun toString(): String = + when { experiment != null -> "Location{experiment=$experiment}" function != null -> "Location{function=$function}" _json != null -> "Location{_unknown=$_json}" else -> throw IllegalStateException("Invalid Location") } - } companion object { @@ -253,40 +376,66 @@ private constructor( fun ofFunction(function: Function) = Location(function = function) } + /** + * An interface that defines how to map each variant of [Location] to a value of type [T]. + */ interface Visitor { fun visitExperiment(experiment: Experiment): T fun visitFunction(function: Function): T + /** + * Maps an unknown variant of [Location] to a value of type [T]. + * + * An instance of [Location] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Location: $json") } } - class Deserializer : BaseDeserializer(Location::class) { + internal class Deserializer : BaseDeserializer(Location::class) { override fun ObjectCodec.deserialize(node: JsonNode): Location { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Location(experiment = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Location(function = it, _json = json) - } - return Location(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Location(experiment = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Location(function = 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 -> Location(_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() + } } } - class Serializer : BaseSerializer(Location::class) { + internal class Serializer : BaseSerializer(Location::class) { override fun serialize( value: Location, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.experiment != null -> generator.writeObject(value.experiment) @@ -297,120 +446,160 @@ private constructor( } } - @JsonDeserialize(builder = Experiment.Builder::class) - @NoAutoDetect class Experiment + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val type: JsonField, private val evalName: JsonField, private val position: JsonField, - private val additionalProperties: Map, + private val type: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun type(): Type = type.getRequired("type") - + @JsonCreator + private constructor( + @JsonProperty("eval_name") + @ExcludeMissing + evalName: JsonField = JsonMissing.of(), + @JsonProperty("position") + @ExcludeMissing + position: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(evalName, position, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 evalName(): String = evalName.getRequired("eval_name") + /** + * @throws BraintrustInvalidDataException 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 position(): Position = position.getRequired("position") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * @throws BraintrustInvalidDataException 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 [evalName]. + * + * Unlike [evalName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("eval_name") @ExcludeMissing fun _evalName(): JsonField = evalName + + /** + * Returns the raw JSON value of [position]. + * + * Unlike [position], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("position") + @ExcludeMissing + fun _position(): JsonField = position - @JsonProperty("eval_name") @ExcludeMissing fun _evalName() = evalName + /** + * 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 - @JsonProperty("position") @ExcludeMissing fun _position() = position + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Experiment = apply { - if (!validated) { - type() - evalName() - position() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Experiment && - this.type == other.type && - this.evalName == other.evalName && - this.position == other.position && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - evalName, - position, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Experiment{type=$type, evalName=$evalName, position=$position, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Experiment]. + * + * The following fields are required: + * ```kotlin + * .evalName() + * .position() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Experiment]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var evalName: JsonField = JsonMissing.of() - private var position: JsonField = JsonMissing.of() + private var evalName: JsonField? = null + private var position: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(experiment: Experiment) = apply { - this.type = experiment.type - this.evalName = experiment.evalName - this.position = experiment.position - additionalProperties(experiment.additionalProperties) + evalName = experiment.evalName + position = experiment.position + type = experiment.type + additionalProperties = experiment.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun evalName(evalName: String) = evalName(JsonField.of(evalName)) - @JsonProperty("eval_name") - @ExcludeMissing + /** + * Sets [Builder.evalName] to an arbitrary JSON value. + * + * You should usually call [Builder.evalName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun evalName(evalName: JsonField) = apply { this.evalName = evalName } fun position(position: Position) = position(JsonField.of(position)) - @JsonProperty("position") - @ExcludeMissing + /** + * Sets [Builder.position] to an arbitrary JSON value. + * + * You should usually call [Builder.position] with a well-typed [Position] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun position(position: JsonField) = apply { this.position = position } + /** Alias for calling [position] with `Position.ofType(type)`. */ + fun position(type: Position.Type) = position(Position.ofType(type)) + + /** Alias for calling [position] with `Position.ofScorer(scorer)`. */ + fun position(scorer: Position.Scorer) = position(Position.ofScorer(scorer)) + + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -418,284 +607,1119 @@ private constructor( 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 [Experiment]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .evalName() + * .position() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Experiment = Experiment( - type, - evalName, - position, - additionalProperties.toUnmodifiable(), + checkRequired("evalName", evalName), + checkRequired("position", position), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Experiment = apply { + if (validated) { + return@apply + } + + evalName() + position().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (evalName.asKnown() == null) 0 else 1) + + (position.asKnown()?.validity() ?: 0) + + (type.asKnown()?.validity() ?: 0) + @JsonDeserialize(using = Position.Deserializer::class) @JsonSerialize(using = Position.Serializer::class) class Position private constructor( - private val task: Task? = null, + private val type: Type? = null, private val scorer: Scorer? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - - fun task(): Task? = task + fun type(): Type? = type fun scorer(): Scorer? = scorer - fun isTask(): Boolean = task != null + fun isType(): Boolean = type != null fun isScorer(): Boolean = scorer != null - fun asTask(): Task = task.getOrThrow("task") + fun asType(): Type = type.getOrThrow("type") fun asScorer(): Scorer = scorer.getOrThrow("scorer") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - task != null -> visitor.visitTask(task) + fun accept(visitor: Visitor): T = + when { + type != null -> visitor.visitType(type) scorer != null -> visitor.visitScorer(scorer) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Position = apply { - if (!validated) { - if (task == null && scorer == null) { - throw BraintrustInvalidDataException("Unknown Position: $_json") - } - task?.validate() - scorer?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitType(type: Type) { + type.validate() + } + + override fun visitScorer(scorer: Scorer) { + scorer.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitType(type: Type) = type.validity() + + override fun visitScorer(scorer: Scorer) = scorer.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Position && - this.task == other.task && - this.scorer == other.scorer + return other is Position && type == other.type && scorer == other.scorer } - override fun hashCode(): Int { - return Objects.hash(task, scorer) - } + override fun hashCode(): Int = Objects.hash(type, scorer) - override fun toString(): String { - return when { - task != null -> "Position{task=$task}" + override fun toString(): String = + when { + type != null -> "Position{type=$type}" scorer != null -> "Position{scorer=$scorer}" _json != null -> "Position{_unknown=$_json}" else -> throw IllegalStateException("Invalid Position") } - } companion object { - fun ofTask(task: Task) = Position(task = task) + fun ofType(type: Type) = Position(type = type) fun ofScorer(scorer: Scorer) = Position(scorer = scorer) } + /** + * An interface that defines how to map each variant of [Position] to a value of + * type [T]. + */ interface Visitor { - fun visitTask(task: Task): T + fun visitType(type: Type): T fun visitScorer(scorer: Scorer): T + /** + * Maps an unknown variant of [Position] to a value of type [T]. + * + * An instance of [Position] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Position: $json") } } - class Deserializer : BaseDeserializer(Position::class) { + internal class Deserializer : BaseDeserializer(Position::class) { override fun ObjectCodec.deserialize(node: JsonNode): Position { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Position(task = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Position(scorer = it, _json = json) - } - return Position(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Position(type = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Position(scorer = 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 -> Position(_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() + } } } - class Serializer : BaseSerializer(Position::class) { + internal class Serializer : BaseSerializer(Position::class) { override fun serialize( value: Position, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.task != null -> generator.writeObject(value.task) + value.type != null -> generator.writeObject(value.type) value.scorer != null -> generator.writeObject(value.scorer) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Position") } } } - } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + class Type + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of() + ) : this(type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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(): InnerType = type.getRequired("type") + + /** + * 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) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Type]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ + fun builder() = Builder() } - return other is Type && this.value == other.value - } + /** A builder for [Type]. */ + class Builder internal constructor() { - override fun hashCode() = value.hashCode() + private var type: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() - override fun toString() = value.toString() + internal fun from(type: Type) = apply { + this.type = type.type + additionalProperties = type.additionalProperties.toMutableMap() + } - companion object { + fun type(type: InnerType) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [InnerType] + * 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) + } - val EXPERIMENT = Type(JsonField.of("experiment")) + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun of(value: String) = Type(JsonField.of(value)) - } + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } - enum class Known { - EXPERIMENT, - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - enum class Value { - EXPERIMENT, - _UNKNOWN, - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun value(): Value = - when (this) { - EXPERIMENT -> Value.EXPERIMENT - else -> Value._UNKNOWN + /** + * Returns an immutable instance of [Type]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Type = + Type(checkRequired("type", type), additionalProperties.toMutableMap()) } - fun known(): Known = - when (this) { - EXPERIMENT -> Known.EXPERIMENT - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } + private var validated: Boolean = false - fun asString(): String = _value().asStringOrThrow() - } - } + fun validate(): Type = apply { + if (validated) { + return@apply + } - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect - class Function - private constructor( - private val type: JsonField, - private val index: JsonField, - private val additionalProperties: Map, - ) { + type().validate() + validated = true + } - private var validated: Boolean = false + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - private var hashCode: Int = 0 + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (type.asKnown()?.validity() ?: 0) + + class InnerType + @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 { + + val TASK = of("task") + + fun of(value: String) = InnerType(JsonField.of(value)) + } - fun type(): Type = type.getRequired("type") + /** An enum containing [InnerType]'s known values. */ + enum class Known { + TASK + } - fun index(): Long = index.getRequired("index") + /** + * An enum containing [InnerType]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [InnerType] 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 { + TASK, + /** + * An enum member indicating that [InnerType] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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) { + TASK -> Value.TASK + else -> Value._UNKNOWN + } - @JsonProperty("index") @ExcludeMissing fun _index() = index + /** + * 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + TASK -> Known.TASK + else -> + throw BraintrustInvalidDataException( + "Unknown InnerType: $value" + ) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): InnerType = apply { + if (validated) { + return@apply + } - fun validate(): Function = apply { - if (!validated) { - type() - index() - validated = true - } - } + known() + validated = true + } - fun toBuilder() = Builder().from(this) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 InnerType && 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 Type && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Type{type=$type, additionalProperties=$additionalProperties}" + } + + class Scorer + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val index: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("index") + @ExcludeMissing + index: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(index, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 index(): Long = index.getRequired("index") + + /** + * @throws BraintrustInvalidDataException 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 [index]. + * + * Unlike [index], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("index") @ExcludeMissing fun _index(): JsonField = index + + /** + * 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 [Scorer]. + * + * The following fields are required: + * ```kotlin + * .index() + * .type() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [Scorer]. */ + class Builder internal constructor() { + + private var index: JsonField? = null + private var type: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(scorer: Scorer) = apply { + index = scorer.index + type = scorer.type + additionalProperties = scorer.additionalProperties.toMutableMap() + } + + fun index(index: Long) = index(JsonField.of(index)) + + /** + * Sets [Builder.index] to an arbitrary JSON value. + * + * You should usually call [Builder.index] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun index(index: JsonField) = apply { this.index = index } + + 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 [Scorer]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .index() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Scorer = + Scorer( + checkRequired("index", index), + checkRequired("type", type), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Scorer = apply { + if (validated) { + return@apply + } + + index() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (index.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { + + val SCORER = of("scorer") + + fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + SCORER + } + + /** + * 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 { + SCORER, + /** + * 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) { + SCORER -> Value.SCORER + 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + SCORER -> Known.SCORER + else -> throw BraintrustInvalidDataException("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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Scorer && + index == other.index && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(index, type, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Scorer{index=$index, type=$type, additionalProperties=$additionalProperties}" + } + } + + 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 { + + val EXPERIMENT = of("experiment") + + fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + EXPERIMENT + } + + /** + * 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 { + EXPERIMENT, + /** + * 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) { + EXPERIMENT -> Value.EXPERIMENT + 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + EXPERIMENT -> Known.EXPERIMENT + else -> throw BraintrustInvalidDataException("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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Function && - this.type == other.type && - this.index == other.index && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - index, - additionalProperties, - ) - } - return hashCode + return other is Experiment && + evalName == other.evalName && + position == other.position && + type == other.type && + additionalProperties == other.additionalProperties } + private val hashCode: Int by lazy { + Objects.hash(evalName, position, type, additionalProperties) + } + + override fun hashCode(): Int = hashCode + override fun toString() = - "Function{type=$type, index=$index, additionalProperties=$additionalProperties}" + "Experiment{evalName=$evalName, position=$position, type=$type, additionalProperties=$additionalProperties}" + } + + class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val index: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("index") @ExcludeMissing index: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(index, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 index(): Long = index.getRequired("index") + + /** + * @throws BraintrustInvalidDataException 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 [index]. + * + * Unlike [index], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("index") @ExcludeMissing fun _index(): JsonField = index + + /** + * 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 [Function]. + * + * The following fields are required: + * ```kotlin + * .index() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Function]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var index: JsonField = JsonMissing.of() + private var index: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(function: Function) = apply { - this.type = function.type - this.index = function.index - additionalProperties(function.additionalProperties) + index = function.index + type = function.type + additionalProperties = function.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun index(index: Long) = index(JsonField.of(index)) - @JsonProperty("index") - @ExcludeMissing + /** + * Sets [Builder.index] to an arbitrary JSON value. + * + * You should usually call [Builder.index] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun index(index: JsonField) = apply { this.index = index } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -703,219 +1727,430 @@ private constructor( 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .index() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Function = Function( - type, - index, - additionalProperties.toUnmodifiable(), + checkRequired("index", index), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Function = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + index() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (index.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val FUNCTION = Type(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - FUNCTION, + FUNCTION } + /** + * 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 { FUNCTION, + /** + * 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) { FUNCTION -> Value.FUNCTION 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { FUNCTION -> Known.FUNCTION else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Function && + index == other.index && + type == other.type && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(index, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Function{index=$index, type=$type, additionalProperties=$additionalProperties}" } } - @JsonDeserialize(builder = RuntimeContext.Builder::class) - @NoAutoDetect class RuntimeContext + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val runtime: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("runtime") @ExcludeMissing runtime: JsonField = JsonMissing.of(), + @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of(), + ) : this(runtime, version, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 runtime(): Runtime = runtime.getRequired("runtime") + /** + * @throws BraintrustInvalidDataException 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 version(): String = version.getRequired("version") - @JsonProperty("runtime") @ExcludeMissing fun _runtime() = runtime + /** + * Returns the raw JSON value of [runtime]. + * + * Unlike [runtime], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("runtime") @ExcludeMissing fun _runtime(): JsonField = runtime + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): RuntimeContext = apply { - if (!validated) { - runtime() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RuntimeContext && - this.runtime == other.runtime && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtime, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [RuntimeContext]. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RuntimeContext]. */ + class Builder internal constructor() { - private var runtime: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() + private var runtime: JsonField? = null + private var version: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(runtimeContext: RuntimeContext) = apply { - this.runtime = runtimeContext.runtime - this.version = runtimeContext.version - additionalProperties(runtimeContext.additionalProperties) + runtime = runtimeContext.runtime + version = runtimeContext.version + additionalProperties = runtimeContext.additionalProperties.toMutableMap() } fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) - @JsonProperty("runtime") - @ExcludeMissing + /** + * Sets [Builder.runtime] to an arbitrary JSON value. + * + * You should usually call [Builder.runtime] with a well-typed [Runtime] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun runtime(runtime: JsonField) = apply { this.runtime = runtime } fun version(version: String) = version(JsonField.of(version)) - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RuntimeContext]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RuntimeContext = RuntimeContext( - runtime, - version, - additionalProperties.toUnmodifiable(), + checkRequired("runtime", runtime), + checkRequired("version", version), + additionalProperties.toMutableMap(), ) } - class Runtime - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): RuntimeContext = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + runtime().validate() + version() + validated = true + } - return other is Runtime && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (runtime.asKnown()?.validity() ?: 0) + (if (version.asKnown() == null) 0 else 1) + + class Runtime @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 { - val NODE = Runtime(JsonField.of("node")) + val NODE = of("node") - val PYTHON = Runtime(JsonField.of("python")) + val PYTHON = of("python") fun of(value: String) = Runtime(JsonField.of(value)) } + /** An enum containing [Runtime]'s known values. */ enum class Known { NODE, PYTHON, } + /** + * An enum containing [Runtime]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Runtime] 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 { NODE, PYTHON, + /** + * An enum member indicating that [Runtime] 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) { NODE -> Value.NODE @@ -923,6 +2158,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { NODE -> Known.NODE @@ -930,7 +2174,96 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown Runtime: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Runtime = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Runtime && 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 RuntimeContext && + runtime == other.runtime && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(runtime, version, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is CodeBundle && + bundleId == other.bundleId && + location == other.location && + runtimeContext == other.runtimeContext && + preview == other.preview && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { + Objects.hash(bundleId, location, runtimeContext, preview, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CodeBundle{bundleId=$bundleId, location=$location, runtimeContext=$runtimeContext, preview=$preview, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CreateApiKeyOutput.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CreateApiKeyOutput.kt index 8f855251..bf517a28 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CreateApiKeyOutput.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CreateApiKeyOutput.kt @@ -6,231 +6,386 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = CreateApiKeyOutput.Builder::class) -@NoAutoDetect class CreateApiKeyOutput +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val created: JsonField, + private val key: JsonField, private val name: JsonField, private val previewName: JsonField, - private val userId: JsonField, + private val created: JsonField, private val orgId: JsonField, - private val key: JsonField, - private val additionalProperties: Map, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the api key */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("key") @ExcludeMissing key: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("preview_name") + @ExcludeMissing + previewName: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this(id, key, name, previewName, created, orgId, userId, mutableMapOf()) + + /** + * Unique identifier for the api key + * + * @throws BraintrustInvalidDataException 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") - /** Date of api key creation */ - fun created(): OffsetDateTime? = created.getNullable("created") + /** + * The raw API key. It will only be exposed this one time + * + * @throws BraintrustInvalidDataException 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 key(): String = key.getRequired("key") - /** Name of the api key */ + /** + * Name of the api key + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + /** + * @throws BraintrustInvalidDataException 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 previewName(): String = previewName.getRequired("preview_name") - /** Unique identifier for the user */ - fun userId(): String? = userId.getNullable("user_id") + /** + * Date of api key creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") - /** Unique identifier for the organization */ + /** + * Unique identifier for the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun orgId(): String? = orgId.getNullable("org_id") - /** The raw API key. It will only be exposed this one time */ - fun key(): String = key.getRequired("key") - - /** Unique identifier for the api key */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Date of api key creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Name of the api key */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonProperty("preview_name") @ExcludeMissing fun _previewName() = previewName - - /** Unique identifier for the user */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId - - /** Unique identifier for the organization */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId + /** + * Unique identifier for the user + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - /** The raw API key. It will only be exposed this one time */ - @JsonProperty("key") @ExcludeMissing fun _key() = key + /** + * 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 [key]. + * + * Unlike [key], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("key") @ExcludeMissing fun _key(): JsonField = key + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [previewName]. + * + * Unlike [previewName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("preview_name") + @ExcludeMissing + fun _previewName(): JsonField = previewName + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): CreateApiKeyOutput = apply { - if (!validated) { - id() - created() - name() - previewName() - userId() - orgId() - key() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is CreateApiKeyOutput && - this.id == other.id && - this.created == other.created && - this.name == other.name && - this.previewName == other.previewName && - this.userId == other.userId && - this.orgId == other.orgId && - this.key == other.key && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - created, - name, - previewName, - userId, - orgId, - key, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "CreateApiKeyOutput{id=$id, created=$created, name=$name, previewName=$previewName, userId=$userId, orgId=$orgId, key=$key, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [CreateApiKeyOutput]. + * + * The following fields are required: + * ```kotlin + * .id() + * .key() + * .name() + * .previewName() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [CreateApiKeyOutput]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var key: JsonField? = null + private var name: JsonField? = null + private var previewName: JsonField? = null private var created: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var previewName: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() private var orgId: JsonField = JsonMissing.of() - private var key: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(createApiKeyOutput: CreateApiKeyOutput) = apply { - this.id = createApiKeyOutput.id - this.created = createApiKeyOutput.created - this.name = createApiKeyOutput.name - this.previewName = createApiKeyOutput.previewName - this.userId = createApiKeyOutput.userId - this.orgId = createApiKeyOutput.orgId - this.key = createApiKeyOutput.key - additionalProperties(createApiKeyOutput.additionalProperties) + id = createApiKeyOutput.id + key = createApiKeyOutput.key + name = createApiKeyOutput.name + previewName = createApiKeyOutput.previewName + created = createApiKeyOutput.created + orgId = createApiKeyOutput.orgId + userId = createApiKeyOutput.userId + additionalProperties = createApiKeyOutput.additionalProperties.toMutableMap() } /** Unique identifier for the api key */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the api key */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } - /** Date of api key creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** The raw API key. It will only be exposed this one time */ + fun key(key: String) = key(JsonField.of(key)) - /** Date of api key creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } + /** + * Sets [Builder.key] to an arbitrary JSON value. + * + * You should usually call [Builder.key] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun key(key: JsonField) = apply { this.key = key } /** Name of the api key */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the api key */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun previewName(previewName: String) = previewName(JsonField.of(previewName)) - @JsonProperty("preview_name") - @ExcludeMissing + /** + * Sets [Builder.previewName] to an arbitrary JSON value. + * + * You should usually call [Builder.previewName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun previewName(previewName: JsonField) = apply { this.previewName = previewName } - /** Unique identifier for the user */ - fun userId(userId: String) = userId(JsonField.of(userId)) - - /** Unique identifier for the user */ - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } - - /** Unique identifier for the organization */ - fun orgId(orgId: String) = orgId(JsonField.of(orgId)) + /** Date of api key creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } /** Unique identifier for the organization */ - @JsonProperty("org_id") - @ExcludeMissing + fun orgId(orgId: String?) = orgId(JsonField.ofNullable(orgId)) + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun orgId(orgId: JsonField) = apply { this.orgId = orgId } - /** The raw API key. It will only be exposed this one time */ - fun key(key: String) = key(JsonField.of(key)) - - /** The raw API key. It will only be exposed this one time */ - @JsonProperty("key") - @ExcludeMissing - fun key(key: JsonField) = apply { this.key = key } + /** Unique identifier for the user */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [CreateApiKeyOutput]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .key() + * .name() + * .previewName() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): CreateApiKeyOutput = CreateApiKeyOutput( - id, + checkRequired("id", id), + checkRequired("key", key), + checkRequired("name", name), + checkRequired("previewName", previewName), created, - name, - previewName, - userId, orgId, - key, - additionalProperties.toUnmodifiable(), + userId, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): CreateApiKeyOutput = apply { + if (validated) { + return@apply + } + + id() + key() + name() + previewName() + created() + orgId() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (key.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (previewName.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CreateApiKeyOutput && + id == other.id && + key == other.key && + name == other.name && + previewName == other.previewName && + created == other.created && + orgId == other.orgId && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, key, name, previewName, created, orgId, userId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CreateApiKeyOutput{id=$id, key=$key, name=$name, previewName=$previewName, created=$created, orgId=$orgId, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponse.kt index b836efe2..ab65129f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponse.kt @@ -6,370 +6,532 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = CrossObjectInsertResponse.Builder::class) -@NoAutoDetect class CrossObjectInsertResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val experiment: JsonField, private val dataset: JsonField, + private val experiment: JsonField, private val projectLogs: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("dataset") @ExcludeMissing dataset: JsonField = JsonMissing.of(), + @JsonProperty("experiment") + @ExcludeMissing + experiment: JsonField = JsonMissing.of(), + @JsonProperty("project_logs") + @ExcludeMissing + projectLogs: JsonField = JsonMissing.of(), + ) : this(dataset, experiment, projectLogs, mutableMapOf()) + + /** + * A mapping from dataset id to row ids for inserted `events` + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun dataset(): Dataset? = dataset.getNullable("dataset") - /** A mapping from experiment id to row ids for inserted `events` */ + /** + * A mapping from experiment id to row ids for inserted `events` + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun experiment(): Experiment? = experiment.getNullable("experiment") - /** A mapping from dataset id to row ids for inserted `events` */ - fun dataset(): Dataset? = dataset.getNullable("dataset") - - /** A mapping from project id to row ids for inserted `events` */ + /** + * A mapping from project id to row ids for inserted `events` + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun projectLogs(): ProjectLogs? = projectLogs.getNullable("project_logs") - /** A mapping from experiment id to row ids for inserted `events` */ - @JsonProperty("experiment") @ExcludeMissing fun _experiment() = experiment - - /** A mapping from dataset id to row ids for inserted `events` */ - @JsonProperty("dataset") @ExcludeMissing fun _dataset() = dataset + /** + * Returns the raw JSON value of [dataset]. + * + * Unlike [dataset], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dataset") @ExcludeMissing fun _dataset(): JsonField = dataset + + /** + * Returns the raw JSON value of [experiment]. + * + * Unlike [experiment], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("experiment") + @ExcludeMissing + fun _experiment(): JsonField = experiment + + /** + * Returns the raw JSON value of [projectLogs]. + * + * Unlike [projectLogs], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("project_logs") + @ExcludeMissing + fun _projectLogs(): JsonField = projectLogs - /** A mapping from project id to row ids for inserted `events` */ - @JsonProperty("project_logs") @ExcludeMissing fun _projectLogs() = projectLogs + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): CrossObjectInsertResponse = apply { - if (!validated) { - experiment()?.validate() - dataset()?.validate() - projectLogs()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is CrossObjectInsertResponse && - this.experiment == other.experiment && - this.dataset == other.dataset && - this.projectLogs == other.projectLogs && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - experiment, - dataset, - projectLogs, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "CrossObjectInsertResponse{experiment=$experiment, dataset=$dataset, projectLogs=$projectLogs, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [CrossObjectInsertResponse]. + */ fun builder() = Builder() } - class Builder { + /** A builder for [CrossObjectInsertResponse]. */ + class Builder internal constructor() { - private var experiment: JsonField = JsonMissing.of() private var dataset: JsonField = JsonMissing.of() + private var experiment: JsonField = JsonMissing.of() private var projectLogs: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(crossObjectInsertResponse: CrossObjectInsertResponse) = apply { - this.experiment = crossObjectInsertResponse.experiment - this.dataset = crossObjectInsertResponse.dataset - this.projectLogs = crossObjectInsertResponse.projectLogs - additionalProperties(crossObjectInsertResponse.additionalProperties) + dataset = crossObjectInsertResponse.dataset + experiment = crossObjectInsertResponse.experiment + projectLogs = crossObjectInsertResponse.projectLogs + additionalProperties = crossObjectInsertResponse.additionalProperties.toMutableMap() } - /** A mapping from experiment id to row ids for inserted `events` */ - fun experiment(experiment: Experiment) = experiment(JsonField.of(experiment)) - - /** A mapping from experiment id to row ids for inserted `events` */ - @JsonProperty("experiment") - @ExcludeMissing - fun experiment(experiment: JsonField) = apply { this.experiment = experiment } - /** A mapping from dataset id to row ids for inserted `events` */ - fun dataset(dataset: Dataset) = dataset(JsonField.of(dataset)) - - /** A mapping from dataset id to row ids for inserted `events` */ - @JsonProperty("dataset") - @ExcludeMissing + fun dataset(dataset: Dataset?) = dataset(JsonField.ofNullable(dataset)) + + /** + * Sets [Builder.dataset] to an arbitrary JSON value. + * + * You should usually call [Builder.dataset] with a well-typed [Dataset] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun dataset(dataset: JsonField) = apply { this.dataset = dataset } - /** A mapping from project id to row ids for inserted `events` */ - fun projectLogs(projectLogs: ProjectLogs) = projectLogs(JsonField.of(projectLogs)) + /** A mapping from experiment id to row ids for inserted `events` */ + fun experiment(experiment: Experiment?) = experiment(JsonField.ofNullable(experiment)) + + /** + * Sets [Builder.experiment] to an arbitrary JSON value. + * + * You should usually call [Builder.experiment] with a well-typed [Experiment] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun experiment(experiment: JsonField) = apply { this.experiment = experiment } /** A mapping from project id to row ids for inserted `events` */ - @JsonProperty("project_logs") - @ExcludeMissing + fun projectLogs(projectLogs: ProjectLogs?) = projectLogs(JsonField.ofNullable(projectLogs)) + + /** + * Sets [Builder.projectLogs] to an arbitrary JSON value. + * + * You should usually call [Builder.projectLogs] with a well-typed [ProjectLogs] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun projectLogs(projectLogs: JsonField) = apply { this.projectLogs = projectLogs } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [CrossObjectInsertResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): CrossObjectInsertResponse = CrossObjectInsertResponse( - experiment, dataset, + experiment, projectLogs, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): CrossObjectInsertResponse = apply { + if (validated) { + return@apply + } + + dataset()?.validate() + experiment()?.validate() + projectLogs()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (dataset.asKnown()?.validity() ?: 0) + + (experiment.asKnown()?.validity() ?: 0) + + (projectLogs.asKnown()?.validity() ?: 0) + /** A mapping from dataset id to row ids for inserted `events` */ - @JsonDeserialize(builder = Dataset.Builder::class) - @NoAutoDetect class Dataset + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Dataset = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Dataset && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Dataset{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Dataset]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Dataset]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(dataset: Dataset) = apply { - additionalProperties(dataset.additionalProperties) + additionalProperties = dataset.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Dataset = Dataset(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - /** A mapping from experiment id to row ids for inserted `events` */ - @JsonDeserialize(builder = Experiment.Builder::class) - @NoAutoDetect - class Experiment - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Dataset]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Dataset = Dataset(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Dataset = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): Experiment = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Experiment && this.additionalProperties == other.additionalProperties + return other is Dataset && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "Experiment{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = "Dataset{additionalProperties=$additionalProperties}" + } + + /** A mapping from experiment id to row ids for inserted `events` */ + class Experiment + @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 [Experiment]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Experiment]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(experiment: Experiment) = apply { - additionalProperties(experiment.additionalProperties) + additionalProperties = experiment.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Experiment = Experiment(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - /** A mapping from project id to row ids for inserted `events` */ - @JsonDeserialize(builder = ProjectLogs.Builder::class) - @NoAutoDetect - class ProjectLogs - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Experiment]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Experiment = Experiment(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Experiment = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): ProjectLogs = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ProjectLogs && this.additionalProperties == other.additionalProperties + return other is Experiment && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "ProjectLogs{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = "Experiment{additionalProperties=$additionalProperties}" + } + + /** A mapping from project id to row ids for inserted `events` */ + class ProjectLogs + @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 [ProjectLogs]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ProjectLogs]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectLogs: ProjectLogs) = apply { - additionalProperties(projectLogs.additionalProperties) + additionalProperties = projectLogs.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): ProjectLogs = ProjectLogs(additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ProjectLogs]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ProjectLogs = ProjectLogs(additionalProperties.toImmutable()) } + + private var validated: Boolean = false + + fun validate(): ProjectLogs = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ProjectLogs && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "ProjectLogs{additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CrossObjectInsertResponse && + dataset == other.dataset && + experiment == other.experiment && + projectLogs == other.projectLogs && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(dataset, experiment, projectLogs, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CrossObjectInsertResponse{dataset=$dataset, experiment=$experiment, projectLogs=$projectLogs, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DataSummary.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DataSummary.kt index c4bc653c..81fb4d6b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DataSummary.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DataSummary.kt @@ -6,103 +6,173 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** Summary of a dataset's data */ -@JsonDeserialize(builder = DataSummary.Builder::class) -@NoAutoDetect class DataSummary +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val totalRecords: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Total number of records in the dataset */ + @JsonCreator + private constructor( + @JsonProperty("total_records") + @ExcludeMissing + totalRecords: JsonField = JsonMissing.of() + ) : this(totalRecords, mutableMapOf()) + + /** + * Total number of records in the dataset + * + * @throws BraintrustInvalidDataException 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 totalRecords(): Long = totalRecords.getRequired("total_records") - /** Total number of records in the dataset */ - @JsonProperty("total_records") @ExcludeMissing fun _totalRecords() = totalRecords - - @JsonAnyGetter + /** + * Returns the raw JSON value of [totalRecords]. + * + * Unlike [totalRecords], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("total_records") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): DataSummary = apply { - if (!validated) { - totalRecords() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun _totalRecords(): JsonField = totalRecords - return other is DataSummary && - this.totalRecords == other.totalRecords && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(totalRecords, additionalProperties) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "DataSummary{totalRecords=$totalRecords, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [DataSummary]. + * + * The following fields are required: + * ```kotlin + * .totalRecords() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [DataSummary]. */ + class Builder internal constructor() { - private var totalRecords: JsonField = JsonMissing.of() + private var totalRecords: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(dataSummary: DataSummary) = apply { - this.totalRecords = dataSummary.totalRecords - additionalProperties(dataSummary.additionalProperties) + totalRecords = dataSummary.totalRecords + additionalProperties = dataSummary.additionalProperties.toMutableMap() } /** Total number of records in the dataset */ fun totalRecords(totalRecords: Long) = totalRecords(JsonField.of(totalRecords)) - /** Total number of records in the dataset */ - @JsonProperty("total_records") - @ExcludeMissing + /** + * Sets [Builder.totalRecords] to an arbitrary JSON value. + * + * You should usually call [Builder.totalRecords] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun totalRecords(totalRecords: JsonField) = apply { this.totalRecords = totalRecords } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): DataSummary = DataSummary(totalRecords, additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [DataSummary]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .totalRecords() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DataSummary = + DataSummary( + checkRequired("totalRecords", totalRecords), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): DataSummary = apply { + if (validated) { + return@apply + } + + totalRecords() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (totalRecords.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DataSummary && + totalRecords == other.totalRecords && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(totalRecords, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DataSummary{totalRecords=$totalRecords, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Dataset.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Dataset.kt index 19713b76..ea2914bf 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Dataset.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Dataset.kt @@ -6,328 +6,535 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = Dataset.Builder::class) -@NoAutoDetect class Dataset +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val projectId: JsonField, private val name: JsonField, - private val description: JsonField, + private val projectId: JsonField, private val created: JsonField, private val deletedAt: JsonField, - private val userId: JsonField, + private val description: JsonField, private val metadata: JsonField, - private val additionalProperties: Map, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the dataset */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this(id, name, projectId, created, deletedAt, description, metadata, userId, mutableMapOf()) + + /** + * Unique identifier for the dataset + * + * @throws BraintrustInvalidDataException 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") - /** Unique identifier for the project that the dataset belongs under */ - fun projectId(): String = projectId.getRequired("project_id") - - /** Name of the dataset. Within a project, dataset names are unique */ + /** + * Name of the dataset. Within a project, dataset names are unique + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** Textual description of the dataset */ - fun description(): String? = description.getNullable("description") + /** + * Unique identifier for the project that the dataset belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** Date of dataset creation */ + /** + * Date of dataset creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** Date of dataset deletion, or null if the dataset is still active */ + /** + * Date of dataset deletion, or null if the dataset is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - /** Identifies the user who created the dataset */ - fun userId(): String? = userId.getNullable("user_id") + /** + * Textual description of the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - /** User-controlled metadata about the dataset */ + /** + * User-controlled metadata about the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** Unique identifier for the dataset */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Unique identifier for the project that the dataset belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId - - /** Name of the dataset. Within a project, dataset names are unique */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Textual description of the dataset */ - @JsonProperty("description") @ExcludeMissing fun _description() = description - - /** Date of dataset creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Date of dataset deletion, or null if the dataset is still active */ - @JsonProperty("deleted_at") @ExcludeMissing fun _deletedAt() = deletedAt - - /** Identifies the user who created the dataset */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + /** + * Identifies the user who created the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - /** User-controlled metadata about the dataset */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt + + /** + * 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 [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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Dataset = apply { - if (!validated) { - id() - projectId() - name() - description() - created() - deletedAt() - userId() - metadata()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Dataset && - this.id == other.id && - this.projectId == other.projectId && - this.name == other.name && - this.description == other.description && - this.created == other.created && - this.deletedAt == other.deletedAt && - this.userId == other.userId && - this.metadata == other.metadata && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - projectId, - name, - description, - created, - deletedAt, - userId, - metadata, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Dataset{id=$id, projectId=$projectId, name=$name, description=$description, created=$created, deletedAt=$deletedAt, userId=$userId, metadata=$metadata, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Dataset]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Dataset]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var projectId: JsonField? = null private var created: JsonField = JsonMissing.of() private var deletedAt: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(dataset: Dataset) = apply { - this.id = dataset.id - this.projectId = dataset.projectId - this.name = dataset.name - this.description = dataset.description - this.created = dataset.created - this.deletedAt = dataset.deletedAt - this.userId = dataset.userId - this.metadata = dataset.metadata - additionalProperties(dataset.additionalProperties) + id = dataset.id + name = dataset.name + projectId = dataset.projectId + created = dataset.created + deletedAt = dataset.deletedAt + description = dataset.description + metadata = dataset.metadata + userId = dataset.userId + additionalProperties = dataset.additionalProperties.toMutableMap() } /** Unique identifier for the dataset */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the dataset */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** Unique identifier for the project that the dataset belongs under */ - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - /** Unique identifier for the project that the dataset belongs under */ - @JsonProperty("project_id") - @ExcludeMissing - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } + /** + * 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 } /** Name of the dataset. Within a project, dataset names are unique */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the dataset. Within a project, dataset names are unique */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } - /** Textual description of the dataset */ - fun description(description: String) = description(JsonField.of(description)) - - /** Textual description of the dataset */ - @JsonProperty("description") - @ExcludeMissing - fun description(description: JsonField) = apply { this.description = description } + /** Unique identifier for the project that the dataset belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Date of dataset creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** + * 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 } /** Date of dataset creation */ - @JsonProperty("created") - @ExcludeMissing + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } /** Date of dataset deletion, or null if the dataset is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = deletedAt(JsonField.of(deletedAt)) - - /** Date of dataset deletion, or null if the dataset is still active */ - @JsonProperty("deleted_at") - @ExcludeMissing + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } - /** Identifies the user who created the dataset */ - fun userId(userId: String) = userId(JsonField.of(userId)) - - /** Identifies the user who created the dataset */ - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } - - /** User-controlled metadata about the dataset */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + /** Textual description of the dataset */ + fun description(description: String?) = description(JsonField.ofNullable(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 } /** User-controlled metadata about the dataset */ - @JsonProperty("metadata") - @ExcludeMissing + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + /** Identifies the user who created the dataset */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Dataset]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Dataset = Dataset( - id, - projectId, - name, - description, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("projectId", projectId), created, deletedAt, - userId, + description, metadata, - additionalProperties.toUnmodifiable(), + userId, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Dataset = apply { + if (validated) { + return@apply + } + + id() + name() + projectId() + created() + deletedAt() + description() + metadata()?.validate() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + /** User-controlled metadata about the dataset */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Dataset && + id == other.id && + name == other.name && + projectId == other.projectId && + created == other.created && + deletedAt == other.deletedAt && + description == other.description && + metadata == other.metadata && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + projectId, + created, + deletedAt, + description, + metadata, + userId, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Dataset{id=$id, name=$name, projectId=$projectId, created=$created, deletedAt=$deletedAt, description=$description, metadata=$metadata, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetCreateParams.kt index 2402fe78..372e2ae1 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetCreateParams.kt @@ -3,285 +3,722 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new dataset. If there is an existing dataset in the project with the same name as the + * one specified in the request, will return the existing dataset unmodified + */ class DatasetCreateParams -constructor( - private val name: String, - private val projectId: String, - private val description: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun projectId(): String = projectId - - fun description(): String? = description - - internal fun getBody(): DatasetCreateBody { - return DatasetCreateBody( - name, - projectId, - description, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the dataset. Within a project, dataset names are unique + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the dataset belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Textual description of the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * User-controlled metadata about the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + 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 [DatasetCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [DatasetCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = DatasetCreateBody.Builder::class) - @NoAutoDetect - class DatasetCreateBody - internal constructor( - private val name: String?, - private val projectId: String?, - private val description: String?, - private val additionalProperties: Map, - ) { + internal fun from(datasetCreateParams: DatasetCreateParams) = apply { + body = datasetCreateParams.body.toBuilder() + additionalHeaders = datasetCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [projectId] + * - [description] + * - [metadata] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the dataset. Within a project, dataset names are unique */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the dataset belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** Textual description of the dataset */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + /** User-controlled metadata about the dataset */ + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + 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) } - return other is DatasetCreateBody && - this.name == other.name && - this.projectId == other.projectId && - this.description == other.description && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - projectId, - description, - additionalProperties, - ) + 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) } - return hashCode + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - override fun toString() = - "DatasetCreateBody{name=$name, projectId=$projectId, description=$description, additionalProperties=$additionalProperties}" + /** + * Returns an immutable instance of [DatasetCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DatasetCreateParams = + DatasetCreateParams( + 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 name: JsonField, + private val projectId: JsonField, + private val description: JsonField, + private val metadata: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + ) : this(name, projectId, description, metadata, mutableMapOf()) + + /** + * Name of the dataset. Within a project, dataset names are unique + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the dataset belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * Textual description of the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * User-controlled metadata about the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [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 [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata + + @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: + * ```kotlin + * .name() + * .projectId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Body]. */ + class Builder internal constructor() { - private var name: String? = null - private var projectId: String? = null - private var description: String? = null + private var name: JsonField? = null + private var projectId: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(datasetCreateBody: DatasetCreateBody) = apply { - this.name = datasetCreateBody.name - this.projectId = datasetCreateBody.projectId - this.description = datasetCreateBody.description - additionalProperties(datasetCreateBody.additionalProperties) + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + description = body.description + metadata = body.metadata + additionalProperties = body.additionalProperties.toMutableMap() } /** Name of the dataset. Within a project, dataset names are unique */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } /** Unique identifier for the project that the dataset belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + 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 } /** Textual description of the dataset */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** User-controlled metadata about the dataset */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): DatasetCreateBody = - DatasetCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, + 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: + * ```kotlin + * .name() + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), description, - additionalProperties.toUnmodifiable(), + metadata, + additionalProperties.toMutableMap(), ) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - fun _additionalHeaders(): Map> = additionalHeaders + private var validated: Boolean = false - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun validate(): Body = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + name() + projectId() + description() + metadata()?.validate() + validated = true } - return other is DatasetCreateParams && - this.name == other.name && - this.projectId == other.projectId && - this.description == other.description && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - override fun hashCode(): Int { - return Objects.hash( - name, - projectId, - description, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) - override fun toString() = - "DatasetCreateParams{name=$name, projectId=$projectId, description=$description, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun toBuilder() = Builder().from(this) + return other is Body && + name == other.name && + projectId == other.projectId && + description == other.description && + metadata == other.metadata && + additionalProperties == other.additionalProperties + } - companion object { + private val hashCode: Int by lazy { + Objects.hash(name, projectId, description, metadata, additionalProperties) + } - fun builder() = Builder() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, projectId=$projectId, description=$description, metadata=$metadata, additionalProperties=$additionalProperties}" } - @NoAutoDetect - class Builder { + /** User-controlled metadata about the dataset */ + class Metadata + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties - private var name: String? = null - private var projectId: String? = null - private var description: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(datasetCreateParams: DatasetCreateParams) = apply { - this.name = datasetCreateParams.name - this.projectId = datasetCreateParams.projectId - this.description = datasetCreateParams.description - additionalQueryParams(datasetCreateParams.additionalQueryParams) - additionalHeaders(datasetCreateParams.additionalHeaders) - additionalBodyProperties(datasetCreateParams.additionalBodyProperties) + companion object { + + /** Returns a mutable builder for constructing an instance of [Metadata]. */ + fun builder() = Builder() } - /** Name of the dataset. Within a project, dataset names are unique */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Metadata]. */ + class Builder internal constructor() { - /** Unique identifier for the project that the dataset belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var additionalProperties: MutableMap = mutableMapOf() - /** Textual description of the dataset */ - fun description(description: String) = apply { this.description = description } + internal fun from(metadata: Metadata) = apply { + additionalProperties = metadata.additionalProperties.toMutableMap() + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + /** + * Returns an immutable instance of [Metadata]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Metadata = Metadata(additionalProperties.toImmutable()) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + private var validated: Boolean = false - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun validate(): Metadata = apply { + if (validated) { + return@apply + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && additionalProperties == other.additionalProperties } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - fun build(): DatasetCreateParams = - DatasetCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - description, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun hashCode(): Int = hashCode + + override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "DatasetCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetDeleteParams.kt index 55f0472d..2f5d5737 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a dataset object by its id */ class DatasetDeleteParams -constructor( - private val datasetId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val datasetId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun datasetId(): String = datasetId + /** Dataset id */ + fun datasetId(): String? = datasetId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): DatasetDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [DatasetDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [DatasetDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var datasetId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(datasetDeleteParams: DatasetDeleteParams) = apply { + datasetId = datasetDeleteParams.datasetId + additionalHeaders = datasetDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = datasetDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Dataset id */ + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is DatasetDeleteParams && - this.datasetId == other.datasetId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - datasetId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "DatasetDeleteParams{datasetId=$datasetId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var datasetId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(datasetDeleteParams: DatasetDeleteParams) = apply { - this.datasetId = datasetDeleteParams.datasetId - additionalQueryParams(datasetDeleteParams.additionalQueryParams) - additionalHeaders(datasetDeleteParams.additionalHeaders) - additionalBodyProperties(datasetDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [DatasetDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): DatasetDeleteParams = DatasetDeleteParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + datasetId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + 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 DatasetDeleteParams && + datasetId == other.datasetId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(datasetId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "DatasetDeleteParams{datasetId=$datasetId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetEvent.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetEvent.kt index c0b4a52f..a83e1ebc 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetEvent.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetEvent.kt @@ -6,40 +6,81 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = DatasetEvent.Builder::class) -@NoAutoDetect class DatasetEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val _xactId: JsonField, private val created: JsonField, - private val projectId: JsonField, private val datasetId: JsonField, - private val input: JsonValue, + private val projectId: JsonField, + private val rootSpanId: JsonField, + private val spanId: JsonField, private val expected: JsonValue, + private val input: JsonValue, + private val isRoot: JsonField, private val metadata: JsonField, + private val origin: JsonField, private val tags: JsonField>, - private val spanId: JsonField, - private val rootSpanId: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_xact_id") @ExcludeMissing _xactId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("dataset_id") @ExcludeMissing datasetId: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("span_id") @ExcludeMissing spanId: JsonField = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonValue = JsonMissing.of(), + @JsonProperty("is_root") @ExcludeMissing isRoot: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("origin") + @ExcludeMissing + origin: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _xactId, + created, + datasetId, + projectId, + rootSpanId, + spanId, + expected, + input, + isRoot, + metadata, + origin, + tags, + mutableMapOf(), + ) /** * A unique identifier for the dataset event. If you don't provide one, BrainTrust will generate * one for you + * + * @throws BraintrustInvalidDataException 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") @@ -47,26 +88,70 @@ private constructor( * The transaction id of an event is unique to the network operation that processed the event * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve * a versioned snapshot of the dataset (see the `version` parameter) + * + * @throws BraintrustInvalidDataException 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 _xactId(): String = _xactId.getRequired("_xact_id") - /** The timestamp the dataset event was created */ + /** + * The timestamp the dataset event was created + * + * @throws BraintrustInvalidDataException 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 created(): OffsetDateTime = created.getRequired("created") - /** Unique identifier for the project that the dataset belongs under */ + /** + * Unique identifier for the dataset + * + * @throws BraintrustInvalidDataException 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 datasetId(): String = datasetId.getRequired("dataset_id") + + /** + * Unique identifier for the project that the dataset belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** Unique identifier for the dataset */ - fun datasetId(): String = datasetId.getRequired("dataset_id") + /** + * A unique identifier for the trace this dataset event belongs to + * + * @throws BraintrustInvalidDataException 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 rootSpanId(): String = rootSpanId.getRequired("root_span_id") - /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ - fun input(): JsonValue = input + /** + * A unique identifier used to link different dataset events together as part of a full trace. + * See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full details on + * tracing + * + * @throws BraintrustInvalidDataException 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 spanId(): String = spanId.getRequired("span_id") /** * The output of your application, including post-processing (an arbitrary, JSON serializable * object) */ - fun expected(): JsonValue = expected + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected + + /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonValue = input + + /** + * Whether this span is a root span + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun isRoot(): Boolean? = isRoot.getNullable("is_root") /** * A dictionary with additional data about the test example, model outputs, or just about @@ -74,175 +159,169 @@ private constructor( * example, you could log the `prompt`, example's `id`, or anything else that would be useful to * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys * must be strings + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") + /** + * Indicates the event was copied from another object. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun origin(): ObjectReference? = origin.getNullable("origin") /** - * A unique identifier used to link different dataset events together as part of a full trace. - * See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full details on - * tracing + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun spanId(): String = spanId.getRequired("span_id") + fun tags(): List? = tags.getNullable("tags") - /** The `span_id` of the root of the trace this dataset event belongs to */ - fun rootSpanId(): String = rootSpanId.getRequired("root_span_id") + /** + * 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 /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will generate - * one for you + * Returns the raw JSON value of [_xactId]. + * + * Unlike [_xactId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("id") @ExcludeMissing fun _id() = id + @JsonProperty("_xact_id") @ExcludeMissing fun __xactId(): JsonField = _xactId /** - * The transaction id of an event is unique to the network operation that processed the event - * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve - * a versioned snapshot of the dataset (see the `version` parameter) + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("_xact_id") @ExcludeMissing fun __xactId() = _xactId + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - /** The timestamp the dataset event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * Returns the raw JSON value of [datasetId]. + * + * Unlike [datasetId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dataset_id") @ExcludeMissing fun _datasetId(): JsonField = datasetId - /** Unique identifier for the project that the dataset belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId + /** + * 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 - /** Unique identifier for the dataset */ - @JsonProperty("dataset_id") @ExcludeMissing fun _datasetId() = datasetId + /** + * Returns the raw JSON value of [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId(): JsonField = rootSpanId - /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ - @JsonProperty("input") @ExcludeMissing fun _input() = input + /** + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object) + * Returns the raw JSON value of [isRoot]. + * + * Unlike [isRoot], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected + @JsonProperty("is_root") @ExcludeMissing fun _isRoot(): JsonField = isRoot /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings + * 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() = metadata + @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin /** - * A unique identifier used to link different dataset events together as part of a full trace. - * See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full details on - * tracing + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("span_id") @ExcludeMissing fun _spanId() = spanId + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - /** The `span_id` of the root of the trace this dataset event belongs to */ - @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId() = rootSpanId + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): DatasetEvent = apply { - if (!validated) { - id() - _xactId() - created() - projectId() - datasetId() - input() - expected() - metadata()?.validate() - tags() - spanId() - rootSpanId() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is DatasetEvent && - this.id == other.id && - this._xactId == other._xactId && - this.created == other.created && - this.projectId == other.projectId && - this.datasetId == other.datasetId && - this.input == other.input && - this.expected == other.expected && - this.metadata == other.metadata && - this.tags == other.tags && - this.spanId == other.spanId && - this.rootSpanId == other.rootSpanId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - _xactId, - created, - projectId, - datasetId, - input, - expected, - metadata, - tags, - spanId, - rootSpanId, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "DatasetEvent{id=$id, _xactId=$_xactId, created=$created, projectId=$projectId, datasetId=$datasetId, input=$input, expected=$expected, metadata=$metadata, tags=$tags, spanId=$spanId, rootSpanId=$rootSpanId, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [DatasetEvent]. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .created() + * .datasetId() + * .projectId() + * .rootSpanId() + * .spanId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [DatasetEvent]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var _xactId: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var datasetId: JsonField = JsonMissing.of() - private var input: JsonValue = JsonMissing.of() + private var id: JsonField? = null + private var _xactId: JsonField? = null + private var created: JsonField? = null + private var datasetId: JsonField? = null + private var projectId: JsonField? = null + private var rootSpanId: JsonField? = null + private var spanId: JsonField? = null private var expected: JsonValue = JsonMissing.of() + private var input: JsonValue = JsonMissing.of() + private var isRoot: JsonField = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var spanId: JsonField = JsonMissing.of() - private var rootSpanId: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(datasetEvent: DatasetEvent) = apply { - this.id = datasetEvent.id - this._xactId = datasetEvent._xactId - this.created = datasetEvent.created - this.projectId = datasetEvent.projectId - this.datasetId = datasetEvent.datasetId - this.input = datasetEvent.input - this.expected = datasetEvent.expected - this.metadata = datasetEvent.metadata - this.tags = datasetEvent.tags - this.spanId = datasetEvent.spanId - this.rootSpanId = datasetEvent.rootSpanId - additionalProperties(datasetEvent.additionalProperties) + id = datasetEvent.id + _xactId = datasetEvent._xactId + created = datasetEvent.created + datasetId = datasetEvent.datasetId + projectId = datasetEvent.projectId + rootSpanId = datasetEvent.rootSpanId + spanId = datasetEvent.spanId + expected = datasetEvent.expected + input = datasetEvent.input + isRoot = datasetEvent.isRoot + metadata = datasetEvent.metadata + origin = datasetEvent.origin + tags = datasetEvent.tags.map { it.toMutableList() } + additionalProperties = datasetEvent.additionalProperties.toMutableMap() } /** @@ -252,10 +331,12 @@ private constructor( fun id(id: String) = id(JsonField.of(id)) /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will - * generate one for you + * 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. */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } + fun id(id: JsonField) = apply { this.id = id } /** * The transaction id of an event is unique to the network operation that processed the @@ -265,61 +346,104 @@ private constructor( fun _xactId(_xactId: String) = _xactId(JsonField.of(_xactId)) /** - * The transaction id of an event is unique to the network operation that processed the - * event insertion. Transaction ids are monotonically increasing over time and can be used - * to retrieve a versioned snapshot of the dataset (see the `version` parameter) + * Sets [Builder._xactId] to an arbitrary JSON value. + * + * You should usually call [Builder._xactId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("_xact_id") - @ExcludeMissing fun _xactId(_xactId: JsonField) = apply { this._xactId = _xactId } /** The timestamp the dataset event was created */ fun created(created: OffsetDateTime) = created(JsonField.of(created)) - /** The timestamp the dataset event was created */ - @JsonProperty("created") - @ExcludeMissing + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } + /** Unique identifier for the dataset */ + fun datasetId(datasetId: String) = datasetId(JsonField.of(datasetId)) + + /** + * Sets [Builder.datasetId] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun datasetId(datasetId: JsonField) = apply { this.datasetId = datasetId } + /** Unique identifier for the project that the dataset belongs under */ fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Unique identifier for the project that the dataset belongs under */ - @JsonProperty("project_id") - @ExcludeMissing + /** + * 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 } - /** Unique identifier for the dataset */ - fun datasetId(datasetId: String) = datasetId(JsonField.of(datasetId)) + /** A unique identifier for the trace this dataset event belongs to */ + fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) - /** Unique identifier for the dataset */ - @JsonProperty("dataset_id") - @ExcludeMissing - fun datasetId(datasetId: JsonField) = apply { this.datasetId = datasetId } + /** + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } /** - * The argument that uniquely define an input case (an arbitrary, JSON serializable object) + * A unique identifier used to link different dataset events together as part of a full + * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full + * details on tracing */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } + fun spanId(spanId: String) = spanId(JsonField.of(spanId)) + + /** + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } /** * The output of your application, including post-processing (an arbitrary, JSON * serializable object) */ - @JsonProperty("expected") - @ExcludeMissing fun expected(expected: JsonValue) = apply { this.expected = expected } /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings + * The argument that uniquely define an input case (an arbitrary, JSON serializable object) + */ + fun input(input: JsonValue) = apply { this.input = input } + + /** Whether this span is a root span */ + fun isRoot(isRoot: Boolean?) = isRoot(JsonField.ofNullable(isRoot)) + + /** + * Alias for [Builder.isRoot]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun isRoot(isRoot: Boolean) = isRoot(isRoot as Boolean?) + + /** + * Sets [Builder.isRoot] to an arbitrary JSON value. + * + * You should usually call [Builder.isRoot] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun isRoot(isRoot: JsonField) = apply { this.isRoot = isRoot } /** * A dictionary with additional data about the test example, model outputs, or just about @@ -328,73 +452,155 @@ private constructor( * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, * but its keys must be strings */ - @JsonProperty("metadata") - @ExcludeMissing + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) + /** Indicates the event was copied from another object. */ + fun origin(origin: ObjectReference?) = origin(JsonField.ofNullable(origin)) + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [ObjectReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun origin(origin: JsonField) = apply { this.origin = origin } /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) /** - * A unique identifier used to link different dataset events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun spanId(spanId: String) = spanId(JsonField.of(spanId)) + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } /** - * A unique identifier used to link different dataset events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. */ - @JsonProperty("span_id") - @ExcludeMissing - fun spanId(spanId: JsonField) = apply { this.spanId = spanId } - - /** The `span_id` of the root of the trace this dataset event belongs to */ - fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) - - /** The `span_id` of the root of the trace this dataset event belongs to */ - @JsonProperty("root_span_id") - @ExcludeMissing - fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [DatasetEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .created() + * .datasetId() + * .projectId() + * .rootSpanId() + * .spanId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): DatasetEvent = DatasetEvent( - id, - _xactId, - created, - projectId, - datasetId, - input, + checkRequired("id", id), + checkRequired("_xactId", _xactId), + checkRequired("created", created), + checkRequired("datasetId", datasetId), + checkRequired("projectId", projectId), + checkRequired("rootSpanId", rootSpanId), + checkRequired("spanId", spanId), expected, + input, + isRoot, metadata, - tags.map { it.toUnmodifiable() }, - spanId, - rootSpanId, - additionalProperties.toUnmodifiable(), + origin, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): DatasetEvent = apply { + if (validated) { + return@apply + } + + id() + _xactId() + created() + datasetId() + projectId() + rootSpanId() + spanId() + isRoot() + metadata()?.validate() + origin()?.validate() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_xactId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (datasetId.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (if (spanId.asKnown() == null) 0 else 1) + + (if (isRoot.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + /** * A dictionary with additional data about the test example, model outputs, or just about * anything else that's relevant, that you can use to help find and analyze examples later. For @@ -402,74 +608,189 @@ private constructor( * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys * must be strings */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val additionalProperties: Map, + private val model: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of() + ) : this(model, mutableMapOf()) - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) + /** + * The model used for this example + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): String? = model.getNullable("model") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * 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 - return other is Metadata && this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { + private var model: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + model = metadata.model + additionalProperties = metadata.additionalProperties.toMutableMap() } + /** The model used for this example */ + fun model(model: String?) = model(JsonField.ofNullable(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 additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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(model, additionalProperties.toMutableMap()) } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + model() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (model.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && + model == other.model && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(model, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metadata{model=$model, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetEvent && + id == other.id && + _xactId == other._xactId && + created == other.created && + datasetId == other.datasetId && + projectId == other.projectId && + rootSpanId == other.rootSpanId && + spanId == other.spanId && + expected == other.expected && + input == other.input && + isRoot == other.isRoot && + metadata == other.metadata && + origin == other.origin && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + _xactId, + created, + datasetId, + projectId, + rootSpanId, + spanId, + expected, + input, + isRoot, + metadata, + origin, + tags, + additionalProperties, + ) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DatasetEvent{id=$id, _xactId=$_xactId, created=$created, datasetId=$datasetId, projectId=$projectId, rootSpanId=$rootSpanId, spanId=$spanId, expected=$expected, input=$input, isRoot=$isRoot, metadata=$metadata, origin=$origin, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFeedbackParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFeedbackParams.kt index caaa6cb1..bd9a676f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFeedbackParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFeedbackParams.kt @@ -3,255 +3,462 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** Log feedback for a set of dataset events */ class DatasetFeedbackParams -constructor( - private val datasetId: String, - private val feedback: List, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val datasetId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Dataset id */ + fun datasetId(): String? = datasetId + + /** + * A list of dataset feedback items + * + * @throws BraintrustInvalidDataException 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 feedback(): List = body.feedback() + + /** + * Returns the raw JSON value of [feedback]. + * + * Unlike [feedback], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _feedback(): JsonField> = body._feedback() + + 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 datasetId(): String = datasetId + fun toBuilder() = Builder().from(this) - fun feedback(): List = feedback + companion object { - internal fun getBody(): DatasetFeedbackBody { - return DatasetFeedbackBody(feedback, additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [DatasetFeedbackParams]. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [DatasetFeedbackParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var datasetId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" + internal fun from(datasetFeedbackParams: DatasetFeedbackParams) = apply { + datasetId = datasetFeedbackParams.datasetId + body = datasetFeedbackParams.body.toBuilder() + additionalHeaders = datasetFeedbackParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetFeedbackParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = DatasetFeedbackBody.Builder::class) - @NoAutoDetect - class DatasetFeedbackBody - internal constructor( - private val feedback: List?, - private val additionalProperties: Map, - ) { + /** Dataset id */ + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } - private var hashCode: Int = 0 + /** + * 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: + * - [feedback] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** A list of dataset feedback items */ - @JsonProperty("feedback") fun feedback(): List? = feedback + fun feedback(feedback: List) = apply { body.feedback(feedback) } + + /** + * Sets [Builder.feedback] to an arbitrary JSON value. + * + * You should usually call [Builder.feedback] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun feedback(feedback: JsonField>) = apply { + body.feedback(feedback) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Adds a single [FeedbackDatasetItem] to [Builder.feedback]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFeedback(feedback: FeedbackDatasetItem) = apply { body.addFeedback(feedback) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is DatasetFeedbackBody && - this.feedback == other.feedback && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(feedback, additionalProperties) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "DatasetFeedbackBody{feedback=$feedback, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var feedback: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(datasetFeedbackBody: DatasetFeedbackBody) = apply { - this.feedback = datasetFeedbackBody.feedback - additionalProperties(datasetFeedbackBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** A list of dataset feedback items */ - @JsonProperty("feedback") - fun feedback(feedback: List) = apply { this.feedback = feedback } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun build(): DatasetFeedbackBody = - DatasetFeedbackBody( - checkNotNull(feedback) { "`feedback` is required but was not set" } - .toUnmodifiable(), - additionalProperties.toUnmodifiable() - ) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - fun _additionalHeaders(): Map> = additionalHeaders + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - return other is DatasetFeedbackParams && - this.datasetId == other.datasetId && - this.feedback == other.feedback && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - datasetId, - feedback, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun toString() = - "DatasetFeedbackParams{datasetId=$datasetId, feedback=$feedback, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - companion object { + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun builder() = Builder() - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - @NoAutoDetect - class Builder { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - private var datasetId: String? = null - private var feedback: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - internal fun from(datasetFeedbackParams: DatasetFeedbackParams) = apply { - this.datasetId = datasetFeedbackParams.datasetId - this.feedback(datasetFeedbackParams.feedback) - additionalQueryParams(datasetFeedbackParams.additionalQueryParams) - additionalHeaders(datasetFeedbackParams.additionalHeaders) - additionalBodyProperties(datasetFeedbackParams.additionalBodyProperties) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + /** + * Returns an immutable instance of [DatasetFeedbackParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DatasetFeedbackParams = + DatasetFeedbackParams( + datasetId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } - /** A list of dataset feedback items */ - fun feedback(feedback: List) = apply { - this.feedback.clear() - this.feedback.addAll(feedback) + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + else -> "" } - /** A list of dataset feedback items */ - fun addFeedback(feedback: FeedbackDatasetItem) = apply { this.feedback.add(feedback) } + override fun _headers(): Headers = additionalHeaders - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + override fun _queryParams(): QueryParams = additionalQueryParams - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val feedback: JsonField>, + private val additionalProperties: MutableMap, + ) { - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + @JsonCreator + private constructor( + @JsonProperty("feedback") + @ExcludeMissing + feedback: JsonField> = JsonMissing.of() + ) : this(feedback, mutableMapOf()) + + /** + * A list of dataset feedback items + * + * @throws BraintrustInvalidDataException 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 feedback(): List = feedback.getRequired("feedback") + + /** + * Returns the raw JSON value of [feedback]. + * + * Unlike [feedback], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("feedback") + @ExcludeMissing + fun _feedback(): JsonField> = feedback - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun toBuilder() = Builder().from(this) - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + companion object { - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + */ + fun builder() = Builder() } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + private var feedback: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + internal fun from(body: Body) = apply { + feedback = body.feedback.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** A list of dataset feedback items */ + fun feedback(feedback: List) = feedback(JsonField.of(feedback)) + + /** + * Sets [Builder.feedback] to an arbitrary JSON value. + * + * You should usually call [Builder.feedback] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun feedback(feedback: JsonField>) = apply { + this.feedback = feedback.map { it.toMutableList() } + } + + /** + * Adds a single [FeedbackDatasetItem] to [Builder.feedback]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFeedback(feedback: FeedbackDatasetItem) = apply { + this.feedback = + (this.feedback ?: JsonField.of(mutableListOf())).also { + checkKnown("feedback", it).add(feedback) + } + } + + 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: + * ```kotlin + * .feedback() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("feedback", feedback).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + feedback().forEach { it.validate() } + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): DatasetFeedbackParams = - DatasetFeedbackParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, - checkNotNull(feedback) { "`feedback` is required but was not set" } - .toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (feedback.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + feedback == other.feedback && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(feedback, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{feedback=$feedback, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetFeedbackParams && + datasetId == other.datasetId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(datasetId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "DatasetFeedbackParams{datasetId=$datasetId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchParams.kt index dbf7f486..873a51c9 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchParams.kt @@ -2,115 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** + * Fetch the events in a dataset. Equivalent to the POST form of the same path, but with the + * parameters in the URL query rather than in the request body. For more complex queries, use the + * `POST /btql` endpoint. + */ class DatasetFetchParams -constructor( - private val datasetId: String, +private constructor( + private val datasetId: String?, private val limit: Long?, private val maxRootSpanId: String?, private val maxXactId: String?, private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - - fun datasetId(): String = datasetId - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Dataset id */ + fun datasetId(): String? = datasetId + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, later + * pages may return rows which showed up in earlier pages, except with an earlier `_xact_id`. + * This happens because pagination occurs over the whole version history of the event log. You + * will most likely want to exclude any such duplicate, outdated rows (by `id`) from your + * combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up with + * more individual rows than the specified limit if you are fetching events containing traces. + */ fun limit(): Long? = limit + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + */ fun maxRootSpanId(): String? = maxRootSpanId + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + */ fun maxXactId(): String? = maxXactId + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use the + * `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + */ fun version(): String? = version - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.maxRootSpanId?.let { params.put("max_root_span_id", listOf(it.toString())) } - this.maxXactId?.let { params.put("max_xact_id", listOf(it.toString())) } - this.version?.let { params.put("version", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" - } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - return other is DatasetFetchParams && - this.datasetId == other.datasetId && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - datasetId, - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "DatasetFetchParams{datasetId=$datasetId, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): DatasetFetchParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [DatasetFetchParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [DatasetFetchParams]. */ + class Builder internal constructor() { private var datasetId: String? = null private var limit: Long? = null private var maxRootSpanId: String? = null private var maxXactId: String? = null private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(datasetFetchParams: DatasetFetchParams) = apply { - this.datasetId = datasetFetchParams.datasetId - this.limit = datasetFetchParams.limit - this.maxRootSpanId = datasetFetchParams.maxRootSpanId - this.maxXactId = datasetFetchParams.maxXactId - this.version = datasetFetchParams.version - additionalQueryParams(datasetFetchParams.additionalQueryParams) - additionalHeaders(datasetFetchParams.additionalHeaders) + datasetId = datasetFetchParams.datasetId + limit = datasetFetchParams.limit + maxRootSpanId = datasetFetchParams.maxRootSpanId + maxXactId = datasetFetchParams.maxXactId + version = datasetFetchParams.version + additionalHeaders = datasetFetchParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetFetchParams.additionalQueryParams.toBuilder() } /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } /** * limit the number of traces fetched @@ -127,7 +133,14 @@ constructor( * with more individual rows than the specified limit if you are fetching events containing * traces. */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -141,7 +154,7 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } + fun maxRootSpanId(maxRootSpanId: String?) = apply { this.maxRootSpanId = maxRootSpanId } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -155,7 +168,7 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun maxXactId(maxXactId: String?) = apply { this.maxXactId = maxXactId } /** * Retrieve a snapshot of events from a past time @@ -163,57 +176,168 @@ constructor( * The version id is essentially a filter on the latest event transaction id. You can use * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. */ - fun version(version: String) = apply { this.version = version } + fun version(version: String?) = apply { this.version = version } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + 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 removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [DatasetFetchParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): DatasetFetchParams = DatasetFetchParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, + datasetId, limit, maxRootSpanId, maxXactId, version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + limit?.let { put("limit", it.toString()) } + maxRootSpanId?.let { put("max_root_span_id", it) } + maxXactId?.let { put("max_xact_id", it) } + version?.let { put("version", it) } + putAll(additionalQueryParams) + } + .build() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetFetchParams && + datasetId == other.datasetId && + limit == other.limit && + maxRootSpanId == other.maxRootSpanId && + maxXactId == other.maxXactId && + version == other.version && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + datasetId, + limit, + maxRootSpanId, + maxXactId, + version, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "DatasetFetchParams{datasetId=$datasetId, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchPostParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchPostParams.kt index 51faeb06..0b980175 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchPostParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetFetchPostParams.kt @@ -3,81 +3,195 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Fetch the events in a dataset. Equivalent to the GET form of the same path, but with the + * parameters in the request body rather than in the URL query. For more complex queries, use the + * `POST /btql` endpoint. + */ class DatasetFetchPostParams -constructor( - private val datasetId: String, - private val cursor: String?, - private val filters: List?, - private val limit: Long?, - private val maxRootSpanId: String?, - private val maxXactId: String?, - private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun datasetId(): String = datasetId - - fun cursor(): String? = cursor - - fun filters(): List? = filters - - fun limit(): Long? = limit - - fun maxRootSpanId(): String? = maxRootSpanId - - fun maxXactId(): String? = maxXactId - - fun version(): String? = version - - internal fun getBody(): DatasetFetchPostBody { - return DatasetFetchPostBody( - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalBodyProperties, - ) +private constructor( + private val datasetId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Dataset id */ + fun datasetId(): String? = datasetId + + /** + * An opaque string to be used as a cursor for the next page of results, in order from latest to + * earliest. + * + * The string can be obtained directly from the `cursor` property of the previous fetch query + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun cursor(): String? = body.cursor() + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, later + * pages may return rows which showed up in earlier pages, except with an earlier `_xact_id`. + * This happens because pagination occurs over the whole version history of the event log. You + * will most likely want to exclude any such duplicate, outdated rows (by `id`) from your + * combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up with + * more individual rows than the specified limit if you are fetching events containing traces. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun limit(): Long? = body.limit() + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun maxRootSpanId(): String? = body.maxRootSpanId() + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun maxXactId(): String? = body.maxXactId() + + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use the + * `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun version(): String? = body.version() + + /** + * Returns the raw JSON value of [cursor]. + * + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _cursor(): JsonField = body._cursor() + + /** + * Returns the raw JSON value of [limit]. + * + * Unlike [limit], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _limit(): JsonField = body._limit() + + /** + * Returns the raw JSON value of [maxRootSpanId]. + * + * Unlike [maxRootSpanId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _maxRootSpanId(): JsonField = body._maxRootSpanId() + + /** + * Returns the raw JSON value of [maxXactId]. + * + * Unlike [maxXactId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _maxXactId(): JsonField = body._maxXactId() + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _version(): JsonField = body._version() + + 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 { + + fun none(): DatasetFetchPostParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [DatasetFetchPostParams]. */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [DatasetFetchPostParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var datasetId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" + internal fun from(datasetFetchPostParams: DatasetFetchPostParams) = apply { + datasetId = datasetFetchPostParams.datasetId + body = datasetFetchPostParams.body.toBuilder() + additionalHeaders = datasetFetchPostParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetFetchPostParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = DatasetFetchPostBody.Builder::class) - @NoAutoDetect - class DatasetFetchPostBody - internal constructor( - private val cursor: String?, - private val filters: List?, - private val limit: Long?, - private val maxRootSpanId: String?, - private val maxXactId: String?, - private val version: String?, - private val additionalProperties: Map, - ) { + /** Dataset id */ + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } - private var hashCode: Int = 0 + /** + * 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: + * - [cursor] + * - [limit] + * - [maxRootSpanId] + * - [maxXactId] + * - [version] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** * An opaque string to be used as a cursor for the next page of results, in order from @@ -86,17 +200,15 @@ constructor( * The string can be obtained directly from the `cursor` property of the previous fetch * query */ - @JsonProperty("cursor") fun cursor(): String? = cursor + fun cursor(cursor: String?) = apply { body.cursor(cursor) } /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. + * Sets [Builder.cursor] to an arbitrary JSON value. * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. + * You should usually call [Builder.cursor] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("filters") fun filters(): List? = filters + fun cursor(cursor: JsonField) = apply { body.cursor(cursor) } /** * limit the number of traces fetched @@ -113,7 +225,22 @@ constructor( * with more individual rows than the specified limit if you are fetching events containing * traces. */ - @JsonProperty("limit") fun limit(): Long? = limit + fun limit(limit: Long?) = apply { body.limit(limit) } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** + * Sets [Builder.limit] to an arbitrary JSON value. + * + * You should usually call [Builder.limit] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun limit(limit: JsonField) = apply { body.limit(limit) } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -127,7 +254,18 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - @JsonProperty("max_root_span_id") fun maxRootSpanId(): String? = maxRootSpanId + fun maxRootSpanId(maxRootSpanId: String?) = apply { body.maxRootSpanId(maxRootSpanId) } + + /** + * Sets [Builder.maxRootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxRootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun maxRootSpanId(maxRootSpanId: JsonField) = apply { + body.maxRootSpanId(maxRootSpanId) + } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -141,7 +279,16 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - @JsonProperty("max_xact_id") fun maxXactId(): String? = maxXactId + fun maxXactId(maxXactId: String?) = apply { body.maxXactId(maxXactId) } + + /** + * Sets [Builder.maxXactId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxXactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun maxXactId(maxXactId: JsonField) = apply { body.maxXactId(maxXactId) } /** * Retrieve a snapshot of events from a past time @@ -149,71 +296,333 @@ constructor( * The version id is essentially a filter on the latest event transaction id. You can use * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. */ - @JsonProperty("version") fun version(): String? = version + fun version(version: String?) = apply { body.version(version) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun version(version: JsonField) = apply { body.version(version) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + 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) } - return other is DatasetFetchPostBody && - this.cursor == other.cursor && - this.filters == other.filters && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalProperties, - ) + 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) } - return hashCode + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - override fun toString() = - "DatasetFetchPostBody{cursor=$cursor, filters=$filters, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalProperties=$additionalProperties}" + /** + * Returns an immutable instance of [DatasetFetchPostParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): DatasetFetchPostParams = + DatasetFetchPostParams( + datasetId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cursor: JsonField, + private val limit: JsonField, + private val maxRootSpanId: JsonField, + private val maxXactId: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cursor") @ExcludeMissing cursor: JsonField = JsonMissing.of(), + @JsonProperty("limit") @ExcludeMissing limit: JsonField = JsonMissing.of(), + @JsonProperty("max_root_span_id") + @ExcludeMissing + maxRootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("max_xact_id") + @ExcludeMissing + maxXactId: JsonField = JsonMissing.of(), + @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of(), + ) : this(cursor, limit, maxRootSpanId, maxXactId, version, mutableMapOf()) + + /** + * An opaque string to be used as a cursor for the next page of results, in order from + * latest to earliest. + * + * The string can be obtained directly from the `cursor` property of the previous fetch + * query + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cursor(): String? = cursor.getNullable("cursor") + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, + * later pages may return rows which showed up in earlier pages, except with an earlier + * `_xact_id`. This happens because pagination occurs over the whole version history of the + * event log. You will most likely want to exclude any such duplicate, outdated rows (by + * `id`) from your combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up + * with more individual rows than the specified limit if you are fetching events containing + * traces. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun limit(): Long? = limit.getNullable("limit") + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of + * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' + * argument going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the + * cursor for the next page can be found as the row with the minimum (earliest) value of the + * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of + * paginating fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxRootSpanId(): String? = maxRootSpanId.getNullable("max_root_span_id") + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of + * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' + * argument going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the + * cursor for the next page can be found as the row with the minimum (earliest) value of the + * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of + * paginating fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxXactId(): String? = maxXactId.getNullable("max_xact_id") + + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use + * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun version(): String? = version.getNullable("version") + + /** + * Returns the raw JSON value of [cursor]. + * + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cursor") @ExcludeMissing fun _cursor(): JsonField = cursor + + /** + * Returns the raw JSON value of [limit]. + * + * Unlike [limit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("limit") @ExcludeMissing fun _limit(): JsonField = limit + + /** + * Returns the raw JSON value of [maxRootSpanId]. + * + * Unlike [maxRootSpanId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("max_root_span_id") + @ExcludeMissing + fun _maxRootSpanId(): JsonField = maxRootSpanId + + /** + * Returns the raw JSON value of [maxXactId]. + * + * Unlike [maxXactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("max_xact_id") @ExcludeMissing fun _maxXactId(): JsonField = maxXactId + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version + + @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]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Body]. */ + class Builder internal constructor() { - private var cursor: String? = null - private var filters: List? = null - private var limit: Long? = null - private var maxRootSpanId: String? = null - private var maxXactId: String? = null - private var version: String? = null + private var cursor: JsonField = JsonMissing.of() + private var limit: JsonField = JsonMissing.of() + private var maxRootSpanId: JsonField = JsonMissing.of() + private var maxXactId: JsonField = JsonMissing.of() + private var version: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(datasetFetchPostBody: DatasetFetchPostBody) = apply { - this.cursor = datasetFetchPostBody.cursor - this.filters = datasetFetchPostBody.filters - this.limit = datasetFetchPostBody.limit - this.maxRootSpanId = datasetFetchPostBody.maxRootSpanId - this.maxXactId = datasetFetchPostBody.maxXactId - this.version = datasetFetchPostBody.version - additionalProperties(datasetFetchPostBody.additionalProperties) + internal fun from(body: Body) = apply { + cursor = body.cursor + limit = body.limit + maxRootSpanId = body.maxRootSpanId + maxXactId = body.maxXactId + version = body.version + additionalProperties = body.additionalProperties.toMutableMap() } /** @@ -223,18 +632,16 @@ constructor( * The string can be obtained directly from the `cursor` property of the previous fetch * query */ - @JsonProperty("cursor") fun cursor(cursor: String) = apply { this.cursor = cursor } + fun cursor(cursor: String?) = cursor(JsonField.ofNullable(cursor)) /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. + * Sets [Builder.cursor] to an arbitrary JSON value. * - * A list of filters on the events to fetch. Currently, only path-lookup type filters - * are supported. + * You should usually call [Builder.cursor] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("filters") - fun filters(filters: List) = apply { this.filters = filters } + fun cursor(cursor: JsonField) = apply { this.cursor = cursor } /** * limit the number of traces fetched @@ -251,7 +658,23 @@ constructor( * with more individual rows than the specified limit if you are fetching events * containing traces. */ - @JsonProperty("limit") fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = limit(JsonField.ofNullable(limit)) + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** + * Sets [Builder.limit] to an arbitrary JSON value. + * + * You should usually call [Builder.limit] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun limit(limit: JsonField) = apply { this.limit = limit } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor @@ -265,8 +688,19 @@ constructor( * the tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an * overview of paginating fetch queries. */ - @JsonProperty("max_root_span_id") - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } + fun maxRootSpanId(maxRootSpanId: String?) = + maxRootSpanId(JsonField.ofNullable(maxRootSpanId)) + + /** + * Sets [Builder.maxRootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxRootSpanId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxRootSpanId(maxRootSpanId: JsonField) = apply { + this.maxRootSpanId = maxRootSpanId + } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor @@ -280,8 +714,16 @@ constructor( * the tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an * overview of paginating fetch queries. */ - @JsonProperty("max_xact_id") - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun maxXactId(maxXactId: String?) = maxXactId(JsonField.ofNullable(maxXactId)) + + /** + * Sets [Builder.maxXactId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxXactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxXactId(maxXactId: JsonField) = apply { this.maxXactId = maxXactId } /** * Retrieve a snapshot of events from a past time @@ -290,265 +732,127 @@ constructor( * use the `max_xact_id` returned by a past fetch as the version to reproduce that exact * fetch. */ - @JsonProperty("version") fun version(version: String) = apply { this.version = version } + fun version(version: String?) = version(JsonField.ofNullable(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): DatasetFetchPostBody = - DatasetFetchPostBody( + 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( cursor, - filters?.toUnmodifiable(), limit, maxRootSpanId, maxXactId, version, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is DatasetFetchPostParams && - this.datasetId == other.datasetId && - this.cursor == other.cursor && - this.filters == other.filters && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int { - return Objects.hash( - datasetId, - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } - - override fun toString() = - "DatasetFetchPostParams{datasetId=$datasetId, cursor=$cursor, filters=$filters, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) - - companion object { - - fun builder() = Builder() - } - - @NoAutoDetect - class Builder { - - private var datasetId: String? = null - private var cursor: String? = null - private var filters: MutableList = mutableListOf() - private var limit: Long? = null - private var maxRootSpanId: String? = null - private var maxXactId: String? = null - private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() - - internal fun from(datasetFetchPostParams: DatasetFetchPostParams) = apply { - this.datasetId = datasetFetchPostParams.datasetId - this.cursor = datasetFetchPostParams.cursor - this.filters(datasetFetchPostParams.filters ?: listOf()) - this.limit = datasetFetchPostParams.limit - this.maxRootSpanId = datasetFetchPostParams.maxRootSpanId - this.maxXactId = datasetFetchPostParams.maxXactId - this.version = datasetFetchPostParams.version - additionalQueryParams(datasetFetchPostParams.additionalQueryParams) - additionalHeaders(datasetFetchPostParams.additionalHeaders) - additionalBodyProperties(datasetFetchPostParams.additionalBodyProperties) - } - /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + private var validated: Boolean = false - /** - * An opaque string to be used as a cursor for the next page of results, in order from - * latest to earliest. - * - * The string can be obtained directly from the `cursor` property of the previous fetch - * query - */ - fun cursor(cursor: String) = apply { this.cursor = cursor } + fun validate(): Body = apply { + if (validated) { + return@apply + } - /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. - * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. - */ - fun filters(filters: List) = apply { - this.filters.clear() - this.filters.addAll(filters) + cursor() + limit() + maxRootSpanId() + maxXactId() + version() + validated = true } - /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. - * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. - */ - fun addFilter(filter: PathLookupFilter) = apply { this.filters.add(filter) } - - /** - * limit the number of traces fetched - * - * Fetch queries may be paginated if the total result size is expected to be large (e.g. - * project_logs which accumulate over a long time). Note that fetch queries only support - * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, - * later pages may return rows which showed up in earlier pages, except with an earlier - * `_xact_id`. This happens because pagination occurs over the whole version history of the - * event log. You will most likely want to exclude any such duplicate, outdated rows (by - * `id`) from your combined result set. - * - * The `limit` parameter controls the number of full traces to return. So you may end up - * with more individual rows than the specified limit if you are fetching events containing - * traces. - */ - fun limit(limit: Long) = apply { this.limit = limit } - - /** - * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of - * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' - * argument going forwards. - * - * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor - * - * Since a paginated fetch query returns results in order from latest to earliest, the - * cursor for the next page can be found as the row with the minimum (earliest) value of the - * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of - * paginating fetch queries. - */ - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } - - /** - * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of - * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' - * argument going forwards. - * - * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor - * - * Since a paginated fetch query returns results in order from latest to earliest, the - * cursor for the next page can be found as the row with the minimum (earliest) value of the - * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of - * paginating fetch queries. - */ - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } /** - * Retrieve a snapshot of events from a past time + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * The version id is essentially a filter on the latest event transaction id. You can use - * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * Used for best match union deserialization. */ - fun version(version: String) = apply { this.version = version } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + internal fun validity(): Int = + (if (cursor.asKnown() == null) 0 else 1) + + (if (limit.asKnown() == null) 0 else 1) + + (if (maxRootSpanId.asKnown() == null) 0 else 1) + + (if (maxXactId.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } - - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } - - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } - - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + return other is Body && + cursor == other.cursor && + limit == other.limit && + maxRootSpanId == other.maxRootSpanId && + maxXactId == other.maxXactId && + version == other.version && + additionalProperties == other.additionalProperties } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + private val hashCode: Int by lazy { + Objects.hash(cursor, limit, maxRootSpanId, maxXactId, version, additionalProperties) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + override fun hashCode(): Int = hashCode - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + override fun toString() = + "Body{cursor=$cursor, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalProperties=$additionalProperties}" + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) - } + return other is DatasetFetchPostParams && + datasetId == other.datasetId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = + Objects.hash(datasetId, body, additionalHeaders, additionalQueryParams) - fun build(): DatasetFetchPostParams = - DatasetFetchPostParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, - cursor, - if (filters.size == 0) null else filters.toUnmodifiable(), - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + override fun toString() = + "DatasetFetchPostParams{datasetId=$datasetId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetInsertParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetInsertParams.kt index 13f32896..a582433e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetInsertParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetInsertParams.kt @@ -2,395 +2,460 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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 +/** Insert a set of events into the dataset */ class DatasetInsertParams -constructor( - private val datasetId: String, - private val events: List, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val datasetId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Dataset id */ + fun datasetId(): String? = datasetId + + /** + * A list of dataset events to insert + * + * @throws BraintrustInvalidDataException 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 events(): List = body.events() + + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _events(): JsonField> = body._events() + + 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 datasetId(): String = datasetId + fun toBuilder() = Builder().from(this) - fun events(): List = events + companion object { - internal fun getBody(): DatasetInsertBody { - return DatasetInsertBody(events, additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [DatasetInsertParams]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [DatasetInsertParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var datasetId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" + internal fun from(datasetInsertParams: DatasetInsertParams) = apply { + datasetId = datasetInsertParams.datasetId + body = datasetInsertParams.body.toBuilder() + additionalHeaders = datasetInsertParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetInsertParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = DatasetInsertBody.Builder::class) - @NoAutoDetect - class DatasetInsertBody - internal constructor( - private val events: List?, - private val additionalProperties: Map, - ) { + /** Dataset id */ + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } - private var hashCode: Int = 0 + /** + * 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: + * - [events] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** A list of dataset events to insert */ - @JsonProperty("events") fun events(): List? = events - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun events(events: List) = apply { body.events(events) } + + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun events(events: JsonField>) = apply { body.events(events) } + + /** + * Adds a single [InsertDatasetEvent] to [events]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEvent(event: InsertDatasetEvent) = apply { body.addEvent(event) } - return other is DatasetInsertBody && - this.events == other.events && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(events, additionalProperties) - } - return hashCode + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) } - override fun toString() = - "DatasetInsertBody{events=$events, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - class Builder { - - private var events: List? = null - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(datasetInsertBody: DatasetInsertBody) = apply { - this.events = datasetInsertBody.events - additionalProperties(datasetInsertBody.additionalProperties) - } - - /** A list of dataset events to insert */ - @JsonProperty("events") fun events(events: List) = apply { this.events = events } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - fun build(): DatasetInsertBody = - DatasetInsertBody( - checkNotNull(events) { "`events` is required but was not set" } - .toUnmodifiable(), - additionalProperties.toUnmodifiable() - ) + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is DatasetInsertParams && - this.datasetId == other.datasetId && - this.events == other.events && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - datasetId, - events, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "DatasetInsertParams{datasetId=$datasetId, events=$events, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var datasetId: String? = null - private var events: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(datasetInsertParams: DatasetInsertParams) = apply { - this.datasetId = datasetInsertParams.datasetId - this.events(datasetInsertParams.events) - additionalQueryParams(datasetInsertParams.additionalQueryParams) - additionalHeaders(datasetInsertParams.additionalHeaders) - additionalBodyProperties(datasetInsertParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** A list of dataset events to insert */ - fun events(events: List) = apply { - this.events.clear() - this.events.addAll(events) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - /** A list of dataset events to insert */ - fun addEvent(event: Event) = apply { this.events.add(event) } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - + /** + * Returns an immutable instance of [DatasetInsertParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): DatasetInsertParams = DatasetInsertParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, - checkNotNull(events) { "`events` is required but was not set" }.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + datasetId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Event.Deserializer::class) - @JsonSerialize(using = Event.Serializer::class) - class Event + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val insertDatasetEventReplace: InsertDatasetEventReplace? = null, - private val insertDatasetEventMerge: InsertDatasetEventMerge? = null, - private val _json: JsonValue? = null, + private val events: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("events") + @ExcludeMissing + events: JsonField> = JsonMissing.of() + ) : this(events, mutableMapOf()) + + /** + * A list of dataset events to insert + * + * @throws BraintrustInvalidDataException 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 events(): List = events.getRequired("events") + + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("events") + @ExcludeMissing + fun _events(): JsonField> = events - fun insertDatasetEventReplace(): InsertDatasetEventReplace? = insertDatasetEventReplace + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - fun insertDatasetEventMerge(): InsertDatasetEventMerge? = insertDatasetEventMerge + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun isInsertDatasetEventReplace(): Boolean = insertDatasetEventReplace != null + fun toBuilder() = Builder().from(this) - fun isInsertDatasetEventMerge(): Boolean = insertDatasetEventMerge != null + companion object { - fun asInsertDatasetEventReplace(): InsertDatasetEventReplace = - insertDatasetEventReplace.getOrThrow("insertDatasetEventReplace") + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ + fun builder() = Builder() + } - fun asInsertDatasetEventMerge(): InsertDatasetEventMerge = - insertDatasetEventMerge.getOrThrow("insertDatasetEventMerge") + /** A builder for [Body]. */ + class Builder internal constructor() { - fun _json(): JsonValue? = _json + private var events: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun accept(visitor: Visitor): T { - return when { - insertDatasetEventReplace != null -> - visitor.visitInsertDatasetEventReplace(insertDatasetEventReplace) - insertDatasetEventMerge != null -> - visitor.visitInsertDatasetEventMerge(insertDatasetEventMerge) - else -> visitor.unknown(_json) + internal fun from(body: Body) = apply { + events = body.events.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() } - } - fun validate(): Event = apply { - if (!validated) { - if (insertDatasetEventReplace == null && insertDatasetEventMerge == null) { - throw BraintrustInvalidDataException("Unknown Event: $_json") - } - insertDatasetEventReplace?.validate() - insertDatasetEventMerge?.validate() - validated = true + /** A list of dataset events to insert */ + fun events(events: List) = events(JsonField.of(events)) + + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun events(events: JsonField>) = apply { + this.events = events.map { it.toMutableList() } } - } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** + * Adds a single [InsertDatasetEvent] to [events]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEvent(event: InsertDatasetEvent) = apply { + events = + (events ?: JsonField.of(mutableListOf())).also { + checkKnown("events", it).add(event) + } } - return other is Event && - this.insertDatasetEventReplace == other.insertDatasetEventReplace && - this.insertDatasetEventMerge == other.insertDatasetEventMerge - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - override fun hashCode(): Int { - return Objects.hash(insertDatasetEventReplace, insertDatasetEventMerge) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - override fun toString(): String { - return when { - insertDatasetEventReplace != null -> - "Event{insertDatasetEventReplace=$insertDatasetEventReplace}" - insertDatasetEventMerge != null -> - "Event{insertDatasetEventMerge=$insertDatasetEventMerge}" - _json != null -> "Event{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Event") + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) } - } - companion object { + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun ofInsertDatasetEventReplace(insertDatasetEventReplace: InsertDatasetEventReplace) = - Event(insertDatasetEventReplace = insertDatasetEventReplace) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun ofInsertDatasetEventMerge(insertDatasetEventMerge: InsertDatasetEventMerge) = - Event(insertDatasetEventMerge = insertDatasetEventMerge) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("events", events).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - interface Visitor { - - fun visitInsertDatasetEventReplace( - insertDatasetEventReplace: InsertDatasetEventReplace - ): T - - fun visitInsertDatasetEventMerge(insertDatasetEventMerge: InsertDatasetEventMerge): T + private var validated: Boolean = false - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Event: $json") + fun validate(): Body = apply { + if (validated) { + return@apply } + + events().forEach { it.validate() } + validated = true } - class Deserializer : BaseDeserializer(Event::class) { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - override fun ObjectCodec.deserialize(node: JsonNode): Event { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Event(insertDatasetEventReplace = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Event(insertDatasetEventMerge = it, _json = json) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (events.asKnown()?.sumOf { it.validity().toInt() } ?: 0) - return Event(_json = json) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Body && + events == other.events && + additionalProperties == other.additionalProperties } - class Serializer : BaseSerializer(Event::class) { - - override fun serialize( - value: Event, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.insertDatasetEventReplace != null -> - generator.writeObject(value.insertDatasetEventReplace) - value.insertDatasetEventMerge != null -> - generator.writeObject(value.insertDatasetEventMerge) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Event") - } - } + private val hashCode: Int by lazy { Objects.hash(events, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Body{events=$events, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is DatasetInsertParams && + datasetId == other.datasetId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(datasetId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "DatasetInsertParams{datasetId=$datasetId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPage.kt index 0963d693..53a24d88 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPage.kt @@ -2,172 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.DatasetService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see DatasetService.list */ class DatasetListPage private constructor( - private val datasetsService: DatasetService, + private val service: DatasetService, private val params: DatasetListParams, - private val response: Response, -) { + private val response: DatasetListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [DatasetListPageResponse], but gracefully handles missing data. + * + * @see DatasetListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is DatasetListPage && - this.datasetsService == other.datasetsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - datasetsService, - params, - response, - ) - } - - override fun toString() = - "DatasetListPage{datasetsService=$datasetsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): DatasetListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - DatasetListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): DatasetListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - DatasetListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): DatasetListPage? { - return getNextPageParams()?.let { datasetsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(datasetsService: DatasetService, params: DatasetListParams, response: Response) = - DatasetListPage( - datasetsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): DatasetListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): DatasetListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): DatasetListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [DatasetListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [DatasetListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: DatasetService? = null + private var params: DatasetListParams? = null + private var response: DatasetListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(datasetListPage: DatasetListPage) = apply { + service = datasetListPage.service + params = datasetListPage.params + response = datasetListPage.response } - override fun toString() = - "DatasetListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: DatasetService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: DatasetListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: DatasetListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [DatasetListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DatasetListPage = + DatasetListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is DatasetListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: DatasetListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "DatasetListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPageAsync.kt index 288f65e9..f7876af6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPageAsync.kt @@ -2,178 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.DatasetServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see DatasetServiceAsync.list */ class DatasetListPageAsync private constructor( - private val datasetsService: DatasetServiceAsync, + private val service: DatasetServiceAsync, private val params: DatasetListParams, - private val response: Response, -) { + private val response: DatasetListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [DatasetListPageResponse], but gracefully handles missing data. + * + * @see DatasetListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is DatasetListPageAsync && - this.datasetsService == other.datasetsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - datasetsService, - params, - response, - ) - } - - override fun toString() = - "DatasetListPageAsync{datasetsService=$datasetsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): DatasetListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - DatasetListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): DatasetListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - DatasetListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): DatasetListPageAsync? { - return getNextPageParams()?.let { datasetsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - datasetsService: DatasetServiceAsync, - params: DatasetListParams, - response: Response - ) = - DatasetListPageAsync( - datasetsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): DatasetListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): DatasetListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): DatasetListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [DatasetListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [DatasetListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: DatasetServiceAsync? = null + private var params: DatasetListParams? = null + private var response: DatasetListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(datasetListPageAsync: DatasetListPageAsync) = apply { + service = datasetListPageAsync.service + params = datasetListPageAsync.params + response = datasetListPageAsync.response } - override fun toString() = - "DatasetListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: DatasetServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: DatasetListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: DatasetListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [DatasetListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DatasetListPageAsync = + DatasetListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is DatasetListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: DatasetListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "DatasetListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPageResponse.kt new file mode 100644 index 00000000..6ec0ff9f --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 DatasetListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of dataset objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [DatasetListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [DatasetListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(datasetListPageResponse: DatasetListPageResponse) = apply { + objects = datasetListPageResponse.objects.map { it.toMutableList() } + additionalProperties = datasetListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of dataset objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Dataset] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Dataset) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [DatasetListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DatasetListPageResponse = + DatasetListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): DatasetListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DatasetListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListParams.kt index e0c99694..2267628b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all datasets. The datasets are sorted by creation date, with the most recently-created + * datasets coming first + */ class DatasetListParams -constructor( +private constructor( private val datasetName: String?, private val endingBefore: String?, private val ids: Ids?, @@ -29,91 +23,67 @@ constructor( private val projectId: String?, private val projectName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + /** Name of the dataset to search for */ fun datasetName(): String? = datasetName + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Project id */ fun projectId(): String? = projectId + /** Name of the project to search for */ fun projectName(): String? = projectName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.datasetName?.let { params.put("dataset_name", listOf(it.toString())) } - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.projectId?.let { params.put("project_id", listOf(it.toString())) } - this.projectName?.let { params.put("project_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is DatasetListParams && - this.datasetName == other.datasetName && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.projectId == other.projectId && - this.projectName == other.projectName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - datasetName, - endingBefore, - ids, - limit, - orgName, - projectId, - projectName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "DatasetListParams{datasetName=$datasetName, endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): DatasetListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [DatasetListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [DatasetListParams]. */ + class Builder internal constructor() { private var datasetName: String? = null private var endingBefore: String? = null @@ -123,24 +93,24 @@ constructor( private var projectId: String? = null private var projectName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(datasetListParams: DatasetListParams) = apply { - this.datasetName = datasetListParams.datasetName - this.endingBefore = datasetListParams.endingBefore - this.ids = datasetListParams.ids - this.limit = datasetListParams.limit - this.orgName = datasetListParams.orgName - this.projectId = datasetListParams.projectId - this.projectName = datasetListParams.projectName - this.startingAfter = datasetListParams.startingAfter - additionalQueryParams(datasetListParams.additionalQueryParams) - additionalHeaders(datasetListParams.additionalHeaders) + datasetName = datasetListParams.datasetName + endingBefore = datasetListParams.endingBefore + ids = datasetListParams.ids + limit = datasetListParams.limit + orgName = datasetListParams.orgName + projectId = datasetListParams.projectId + projectName = datasetListParams.projectName + startingAfter = datasetListParams.startingAfter + additionalHeaders = datasetListParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetListParams.additionalQueryParams.toBuilder() } /** Name of the dataset to search for */ - fun datasetName(datasetName: String) = apply { this.datasetName = datasetName } + fun datasetName(datasetName: String?) = apply { this.datasetName = datasetName } /** * Pagination cursor id. @@ -149,37 +119,38 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String?) = apply { this.projectId = projectId } /** Name of the project to search for */ - fun projectName(projectName: String) = apply { this.projectName = projectName } + fun projectName(projectName: String?) = apply { this.projectName = projectName } /** * Pagination cursor id. @@ -188,48 +159,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [DatasetListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): DatasetListParams = DatasetListParams( datasetName, @@ -240,22 +274,48 @@ constructor( projectId, projectName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + datasetName?.let { put("dataset_name", it) } + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + projectId?.let { put("project_id", it) } + projectName?.let { put("project_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -268,93 +328,78 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is DatasetListParams && + datasetName == other.datasetName && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + projectId == other.projectId && + projectName == other.projectName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + datasetName, + endingBefore, + ids, + limit, + orgName, + projectId, + projectName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "DatasetListParams{datasetName=$datasetName, endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetRetrieveParams.kt index d4143842..8f998fc3 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetRetrieveParams.kt @@ -2,125 +2,188 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a dataset object by its id */ class DatasetRetrieveParams -constructor( - private val datasetId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val datasetId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun datasetId(): String = datasetId + /** Dataset id */ + fun datasetId(): String? = datasetId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): DatasetRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [DatasetRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [DatasetRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var datasetId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(datasetRetrieveParams: DatasetRetrieveParams) = apply { + datasetId = datasetRetrieveParams.datasetId + additionalHeaders = datasetRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetRetrieveParams.additionalQueryParams.toBuilder() } - return other is DatasetRetrieveParams && - this.datasetId == other.datasetId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Dataset id */ + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } - override fun hashCode(): Int { - return Objects.hash( - datasetId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "DatasetRetrieveParams{datasetId=$datasetId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var datasetId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(datasetRetrieveParams: DatasetRetrieveParams) = apply { - this.datasetId = datasetRetrieveParams.datasetId - additionalQueryParams(datasetRetrieveParams.additionalQueryParams) - additionalHeaders(datasetRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [DatasetRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): DatasetRetrieveParams = DatasetRetrieveParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + datasetId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + 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 DatasetRetrieveParams && + datasetId == other.datasetId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(datasetId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "DatasetRetrieveParams{datasetId=$datasetId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetSummarizeParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetSummarizeParams.kt index bb3a46b1..3f749203 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetSummarizeParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetSummarizeParams.kt @@ -2,143 +2,215 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Summarize dataset */ class DatasetSummarizeParams -constructor( - private val datasetId: String, +private constructor( + private val datasetId: String?, private val summarizeData: Boolean?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun datasetId(): String = datasetId + /** Dataset id */ + fun datasetId(): String? = datasetId + /** Whether to summarize the data. If false (or omitted), only the metadata will be returned. */ fun summarizeData(): Boolean? = summarizeData - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.summarizeData?.let { params.put("summarize_data", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" - } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is DatasetSummarizeParams && - this.datasetId == other.datasetId && - this.summarizeData == other.summarizeData && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - datasetId, - summarizeData, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "DatasetSummarizeParams{datasetId=$datasetId, summarizeData=$summarizeData, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): DatasetSummarizeParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [DatasetSummarizeParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [DatasetSummarizeParams]. */ + class Builder internal constructor() { private var datasetId: String? = null private var summarizeData: Boolean? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(datasetSummarizeParams: DatasetSummarizeParams) = apply { - this.datasetId = datasetSummarizeParams.datasetId - this.summarizeData = datasetSummarizeParams.summarizeData - additionalQueryParams(datasetSummarizeParams.additionalQueryParams) - additionalHeaders(datasetSummarizeParams.additionalHeaders) + datasetId = datasetSummarizeParams.datasetId + summarizeData = datasetSummarizeParams.summarizeData + additionalHeaders = datasetSummarizeParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetSummarizeParams.additionalQueryParams.toBuilder() } /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } /** * Whether to summarize the data. If false (or omitted), only the metadata will be returned. */ - fun summarizeData(summarizeData: Boolean) = apply { this.summarizeData = summarizeData } + fun summarizeData(summarizeData: Boolean?) = apply { this.summarizeData = summarizeData } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + /** + * Alias for [Builder.summarizeData]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun summarizeData(summarizeData: Boolean) = summarizeData(summarizeData as Boolean?) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + 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 putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [DatasetSummarizeParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): DatasetSummarizeParams = DatasetSummarizeParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, + datasetId, summarizeData, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + summarizeData?.let { put("summarize_data", it.toString()) } + putAll(additionalQueryParams) + } + .build() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetSummarizeParams && + datasetId == other.datasetId && + summarizeData == other.summarizeData && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(datasetId, summarizeData, additionalHeaders, additionalQueryParams) + + override fun toString() = + "DatasetSummarizeParams{datasetId=$datasetId, summarizeData=$summarizeData, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetUpdateParams.kt index ef13a994..0f0801f6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/DatasetUpdateParams.kt @@ -3,367 +3,640 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update a dataset object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class DatasetUpdateParams -constructor( - private val datasetId: String, - private val description: String?, - private val metadata: Metadata?, - private val name: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun datasetId(): String = datasetId - - fun description(): String? = description - - fun metadata(): Metadata? = metadata - - fun name(): String? = name - - internal fun getBody(): DatasetUpdateBody { - return DatasetUpdateBody( - description, - metadata, - name, - additionalBodyProperties, - ) - } +private constructor( + private val datasetId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Dataset id */ + fun datasetId(): String? = datasetId + + /** + * Textual description of the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * User-controlled metadata about the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * Name of the dataset. Within a project, dataset names are unique + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + 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 - internal fun getQueryParams(): Map> = additionalQueryParams + fun toBuilder() = Builder().from(this) - internal fun getHeaders(): Map> = additionalHeaders + companion object { - fun getPathParam(index: Int): String { - return when (index) { - 0 -> datasetId - else -> "" - } + fun none(): DatasetUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [DatasetUpdateParams]. */ + fun builder() = Builder() } - @JsonDeserialize(builder = DatasetUpdateBody.Builder::class) - @NoAutoDetect - class DatasetUpdateBody - internal constructor( - private val description: String?, - private val metadata: Metadata?, - private val name: String?, - private val additionalProperties: Map, - ) { + /** A builder for [DatasetUpdateParams]. */ + class Builder internal constructor() { + + private var datasetId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var hashCode: Int = 0 + internal fun from(datasetUpdateParams: DatasetUpdateParams) = apply { + datasetId = datasetUpdateParams.datasetId + body = datasetUpdateParams.body.toBuilder() + additionalHeaders = datasetUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = datasetUpdateParams.additionalQueryParams.toBuilder() + } + + /** Dataset id */ + fun datasetId(datasetId: String?) = apply { this.datasetId = datasetId } + + /** + * 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: + * - [description] + * - [metadata] + * - [name] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Textual description of the dataset */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** User-controlled metadata about the dataset */ - @JsonProperty("metadata") fun metadata(): Metadata? = metadata + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } /** Name of the dataset. Within a project, dataset names are unique */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is DatasetUpdateBody && - this.description == other.description && - this.metadata == other.metadata && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - description, - metadata, - name, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "DatasetUpdateBody{description=$description, metadata=$metadata, name=$name, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var description: String? = null - private var metadata: Metadata? = null - private var name: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(datasetUpdateBody: DatasetUpdateBody) = apply { - this.description = datasetUpdateBody.description - this.metadata = datasetUpdateBody.metadata - this.name = datasetUpdateBody.name - additionalProperties(datasetUpdateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Textual description of the dataset */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** User-controlled metadata about the dataset */ - @JsonProperty("metadata") - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Name of the dataset. Within a project, dataset names are unique */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): DatasetUpdateBody = - DatasetUpdateBody( - description, - metadata, - name, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is DatasetUpdateParams && - this.datasetId == other.datasetId && - this.description == other.description && - this.metadata == other.metadata && - this.name == other.name && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [DatasetUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): DatasetUpdateParams = + DatasetUpdateParams( + datasetId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - datasetId, - description, - metadata, - name, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "DatasetUpdateParams{datasetId=$datasetId, description=$description, metadata=$metadata, name=$name, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun _pathParam(index: Int): String = + when (index) { + 0 -> datasetId ?: "" + else -> "" + } - fun toBuilder() = Builder().from(this) + override fun _headers(): Headers = additionalHeaders - companion object { + override fun _queryParams(): QueryParams = additionalQueryParams - fun builder() = Builder() - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val metadata: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { - @NoAutoDetect - class Builder { + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(description, metadata, name, mutableMapOf()) + + /** + * Textual description of the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * User-controlled metadata about the dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + + /** + * Name of the dataset. Within a project, dataset names are unique + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * 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 [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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - private var datasetId: String? = null - private var description: String? = null - private var metadata: Metadata? = null - private var name: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - internal fun from(datasetUpdateParams: DatasetUpdateParams) = apply { - this.datasetId = datasetUpdateParams.datasetId - this.description = datasetUpdateParams.description - this.metadata = datasetUpdateParams.metadata - this.name = datasetUpdateParams.name - additionalQueryParams(datasetUpdateParams.additionalQueryParams) - additionalHeaders(datasetUpdateParams.additionalHeaders) - additionalBodyProperties(datasetUpdateParams.additionalBodyProperties) + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - /** Dataset id */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Textual description of the dataset */ - fun description(description: String) = apply { this.description = description } + private var description: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** User-controlled metadata about the dataset */ - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + internal fun from(body: Body) = apply { + description = body.description + metadata = body.metadata + name = body.name + additionalProperties = body.additionalProperties.toMutableMap() + } - /** Name of the dataset. Within a project, dataset names are unique */ - fun name(name: String) = apply { this.name = name } + /** Textual description of the dataset */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** User-controlled metadata about the dataset */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * 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 putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** Name of the dataset. Within a project, dataset names are unique */ + fun name(name: String?) = name(JsonField.ofNullable(name)) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + 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(description, metadata, name, additionalProperties.toMutableMap()) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + description() + metadata()?.validate() + name() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (description.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + description == other.description && + metadata == other.metadata && + name == other.name && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(description, metadata, name, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): DatasetUpdateParams = - DatasetUpdateParams( - checkNotNull(datasetId) { "`datasetId` is required but was not set" }, - description, - metadata, - name, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{description=$description, metadata=$metadata, name=$name, additionalProperties=$additionalProperties}" } /** User-controlled metadata about the dataset */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is DatasetUpdateParams && + datasetId == other.datasetId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(datasetId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "DatasetUpdateParams{datasetId=$datasetId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVar.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVar.kt index 70f03b32..fa2f95a0 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVar.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVar.kt @@ -7,263 +7,392 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = EnvVar.Builder::class) -@NoAutoDetect class EnvVar +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val objectType: JsonField, - private val objectId: JsonField, private val name: JsonField, + private val objectId: JsonField, + private val objectType: JsonField, private val created: JsonField, private val used: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the environment variable */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("object_id") @ExcludeMissing objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("used") @ExcludeMissing used: JsonField = JsonMissing.of(), + ) : this(id, name, objectId, objectType, created, used, mutableMapOf()) + + /** + * Unique identifier for the environment variable + * + * @throws BraintrustInvalidDataException 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") - /** The type of the object the environment variable is scoped for */ - fun objectType(): ObjectType = objectType.getRequired("object_type") + /** + * The name of the environment variable + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** The id of the object the environment variable is scoped for */ + /** + * The id of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** The name of the environment variable */ - fun name(): String = name.getRequired("name") + /** + * The type of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = objectType.getRequired("object_type") - /** Date of environment variable creation */ + /** + * Date of environment variable creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** Date the environment variable was last used */ + /** + * Date the environment variable was last used + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun used(): OffsetDateTime? = used.getNullable("used") - /** Unique identifier for the environment variable */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** The type of the object the environment variable is scoped for */ - @JsonProperty("object_type") @ExcludeMissing fun _objectType() = objectType - - /** The id of the object the environment variable is scoped for */ - @JsonProperty("object_id") @ExcludeMissing fun _objectId() = objectId - - /** The name of the environment variable */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Date of environment variable creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Date the environment variable was last used */ - @JsonProperty("used") @ExcludeMissing fun _used() = used + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [used]. + * + * Unlike [used], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("used") @ExcludeMissing fun _used(): JsonField = used + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): EnvVar = apply { - if (!validated) { - id() - objectType() - objectId() - name() - created() - used() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is EnvVar && - this.id == other.id && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.name == other.name && - this.created == other.created && - this.used == other.used && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - objectType, - objectId, - name, - created, - used, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "EnvVar{id=$id, objectType=$objectType, objectId=$objectId, name=$name, created=$created, used=$used, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [EnvVar]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [EnvVar]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var objectType: JsonField = JsonMissing.of() - private var objectId: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null private var created: JsonField = JsonMissing.of() private var used: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(envVar: EnvVar) = apply { - this.id = envVar.id - this.objectType = envVar.objectType - this.objectId = envVar.objectId - this.name = envVar.name - this.created = envVar.created - this.used = envVar.used - additionalProperties(envVar.additionalProperties) + id = envVar.id + name = envVar.name + objectId = envVar.objectId + objectType = envVar.objectType + created = envVar.created + used = envVar.used + additionalProperties = envVar.additionalProperties.toMutableMap() } /** Unique identifier for the environment variable */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the environment variable */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } - /** The type of the object the environment variable is scoped for */ - fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) + /** The name of the environment variable */ + fun name(name: String) = name(JsonField.of(name)) - /** The type of the object the environment variable is scoped for */ - @JsonProperty("object_type") - @ExcludeMissing - fun objectType(objectType: JsonField) = apply { this.objectType = objectType } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } /** The id of the object the environment variable is scoped for */ fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - /** The id of the object the environment variable is scoped for */ - @JsonProperty("object_id") - @ExcludeMissing + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - /** The name of the environment variable */ - fun name(name: String) = name(JsonField.of(name)) - - /** The name of the environment variable */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + /** The type of the object the environment variable is scoped for */ + fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) - /** Date of environment variable creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { this.objectType = objectType } /** Date of environment variable creation */ - @JsonProperty("created") - @ExcludeMissing + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } /** Date the environment variable was last used */ - fun used(used: OffsetDateTime) = used(JsonField.of(used)) - - /** Date the environment variable was last used */ - @JsonProperty("used") - @ExcludeMissing + fun used(used: OffsetDateTime?) = used(JsonField.ofNullable(used)) + + /** + * Sets [Builder.used] to an arbitrary JSON value. + * + * You should usually call [Builder.used] with a well-typed [OffsetDateTime] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun used(used: JsonField) = apply { this.used = used } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [EnvVar]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): EnvVar = EnvVar( - id, - objectType, - objectId, - name, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), created, used, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): EnvVar = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + id() + name() + objectId() + objectType().validate() + created() + used() + validated = true + } - return other is ObjectType && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (created.asKnown() == null) 0 else 1) + + (if (used.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + /** The type of the object the environment variable is scoped for */ + class ObjectType @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 { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + val ORGANIZATION = of("organization") - val PROJECT = ObjectType(JsonField.of("project")) + val PROJECT = of("project") - val FUNCTION = ObjectType(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = ObjectType(JsonField.of(value)) } + /** An enum containing [ObjectType]'s known values. */ enum class Known { ORGANIZATION, PROJECT, FUNCTION, } + /** + * An enum containing [ObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ObjectType] 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 { ORGANIZATION, PROJECT, FUNCTION, + /** + * An enum member indicating that [ObjectType] 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) { ORGANIZATION -> Value.ORGANIZATION @@ -272,6 +401,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { ORGANIZATION -> Known.ORGANIZATION @@ -280,6 +418,79 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ObjectType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ObjectType && 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 EnvVar && + id == other.id && + name == other.name && + objectId == other.objectId && + objectType == other.objectType && + created == other.created && + used == other.used && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, name, objectId, objectType, created, used, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "EnvVar{id=$id, name=$name, objectId=$objectId, objectType=$objectType, created=$created, used=$used, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarCreateParams.kt index 9d2cd226..6b0e7cac 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarCreateParams.kt @@ -5,358 +5,666 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new env_var. If there is an existing env_var with the same name as the one specified in + * the request, will return the existing env_var unmodified + */ class EnvVarCreateParams -constructor( - private val name: String, - private val objectId: String, - private val objectType: ObjectType, - private val value: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun objectId(): String = objectId - - fun objectType(): ObjectType = objectType - - fun value(): String? = value - - internal fun getBody(): EnvVarCreateBody { - return EnvVarCreateBody( - name, - objectId, - objectType, - value, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * The name of the environment variable + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * The id of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() + + /** + * The type of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = body.objectType() + + /** + * The value of the environment variable. Will be encrypted at rest. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun value(): String? = body.value() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _value(): JsonField = body._value() + + 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 [EnvVarCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [EnvVarCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = EnvVarCreateBody.Builder::class) - @NoAutoDetect - class EnvVarCreateBody - internal constructor( - private val name: String?, - private val objectId: String?, - private val objectType: ObjectType?, - private val value: String?, - private val additionalProperties: Map, - ) { + internal fun from(envVarCreateParams: EnvVarCreateParams) = apply { + body = envVarCreateParams.body.toBuilder() + additionalHeaders = envVarCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = envVarCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [objectId] + * - [objectType] + * - [value] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** The name of the environment variable */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The id of the object the environment variable is scoped for */ - @JsonProperty("object_id") fun objectId(): String? = objectId + fun objectId(objectId: String) = apply { body.objectId(objectId) } + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } /** The type of the object the environment variable is scoped for */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + fun objectType(objectType: ObjectType) = apply { body.objectType(objectType) } + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } /** The value of the environment variable. Will be encrypted at rest. */ - @JsonProperty("value") fun value(): String? = value + fun value(value: String?) = apply { body.value(value) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun value(value: JsonField) = apply { body.value(value) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is EnvVarCreateBody && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.value == other.value && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - objectId, - objectType, - value, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "EnvVarCreateBody{name=$name, objectId=$objectId, objectType=$objectType, value=$value, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var value: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(envVarCreateBody: EnvVarCreateBody) = apply { - this.name = envVarCreateBody.name - this.objectId = envVarCreateBody.objectId - this.objectType = envVarCreateBody.objectType - this.value = envVarCreateBody.value - additionalProperties(envVarCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** The name of the environment variable */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** The id of the object the environment variable is scoped for */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The type of the object the environment variable is scoped for */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The value of the environment variable. Will be encrypted at rest. */ - @JsonProperty("value") fun value(value: String) = apply { this.value = value } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): EnvVarCreateBody = - EnvVarCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - value, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is EnvVarCreateParams && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.value == other.value && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [EnvVarCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EnvVarCreateParams = + EnvVarCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - objectId, - objectType, - value, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "EnvVarCreateParams{name=$name, objectId=$objectId, objectType=$objectType, value=$value, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val objectId: JsonField, + private val objectType: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this(name, objectId, objectType, value, mutableMapOf()) + + /** + * The name of the environment variable + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * The id of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + + /** + * The type of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = objectType.getRequired("object_type") + + /** + * The value of the environment variable. Will be encrypted at rest. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun value(): String? = value.getNullable("value") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - @NoAutoDetect - class Builder { + fun toBuilder() = Builder().from(this) - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var value: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + companion object { - internal fun from(envVarCreateParams: EnvVarCreateParams) = apply { - this.name = envVarCreateParams.name - this.objectId = envVarCreateParams.objectId - this.objectType = envVarCreateParams.objectType - this.value = envVarCreateParams.value - additionalQueryParams(envVarCreateParams.additionalQueryParams) - additionalHeaders(envVarCreateParams.additionalHeaders) - additionalBodyProperties(envVarCreateParams.additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - /** The name of the environment variable */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** The id of the object the environment variable is scoped for */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + private var name: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** The type of the object the environment variable is scoped for */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + internal fun from(body: Body) = apply { + name = body.name + objectId = body.objectId + objectType = body.objectType + value = body.value + additionalProperties = body.additionalProperties.toMutableMap() + } - /** The value of the environment variable. Will be encrypted at rest. */ - fun value(value: String) = apply { this.value = value } + /** The name of the environment variable */ + fun name(name: String) = name(JsonField.of(name)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** The id of the object the environment variable is scoped for */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** The type of the object the environment variable is scoped for */ + fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** The value of the environment variable. Will be encrypted at rest. */ + fun value(value: String?) = value(JsonField.ofNullable(value)) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun value(value: JsonField) = apply { this.value = value } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + value, + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply } - fun build(): EnvVarCreateParams = - EnvVarCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - value, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + name() + objectId() + objectType().validate() + value() + validated = true + } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (value.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is ObjectType && this.value == other.value + return other is Body && + name == other.name && + objectId == other.objectId && + objectType == other.objectType && + value == other.value && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash(name, objectId, objectType, value, additionalProperties) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, objectId=$objectId, objectType=$objectType, value=$value, additionalProperties=$additionalProperties}" + } + + /** The type of the object the environment variable is scoped for */ + class ObjectType @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 { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + val ORGANIZATION = of("organization") - val PROJECT = ObjectType(JsonField.of("project")) + val PROJECT = of("project") - val FUNCTION = ObjectType(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = ObjectType(JsonField.of(value)) } + /** An enum containing [ObjectType]'s known values. */ enum class Known { ORGANIZATION, PROJECT, FUNCTION, } + /** + * An enum containing [ObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ObjectType] 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 { ORGANIZATION, PROJECT, FUNCTION, + /** + * An enum member indicating that [ObjectType] 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) { ORGANIZATION -> Value.ORGANIZATION @@ -365,6 +673,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { ORGANIZATION -> Known.ORGANIZATION @@ -373,6 +690,71 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ObjectType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ObjectType && 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 EnvVarCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "EnvVarCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarDeleteParams.kt index f60f79d3..4b685a5a 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete an env_var object by its id */ class EnvVarDeleteParams -constructor( - private val envVarId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val envVarId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun envVarId(): String = envVarId + /** EnvVar id */ + fun envVarId(): String? = envVarId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> envVarId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): EnvVarDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [EnvVarDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [EnvVarDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var envVarId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(envVarDeleteParams: EnvVarDeleteParams) = apply { + envVarId = envVarDeleteParams.envVarId + additionalHeaders = envVarDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = envVarDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = envVarDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** EnvVar id */ + fun envVarId(envVarId: String?) = apply { this.envVarId = envVarId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is EnvVarDeleteParams && - this.envVarId == other.envVarId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - envVarId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "EnvVarDeleteParams{envVarId=$envVarId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var envVarId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(envVarDeleteParams: EnvVarDeleteParams) = apply { - this.envVarId = envVarDeleteParams.envVarId - additionalQueryParams(envVarDeleteParams.additionalQueryParams) - additionalHeaders(envVarDeleteParams.additionalHeaders) - additionalBodyProperties(envVarDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** EnvVar id */ - fun envVarId(envVarId: String) = apply { this.envVarId = envVarId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [EnvVarDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): EnvVarDeleteParams = EnvVarDeleteParams( - checkNotNull(envVarId) { "`envVarId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + envVarId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> envVarId ?: "" + 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 EnvVarDeleteParams && + envVarId == other.envVarId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(envVarId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "EnvVarDeleteParams{envVarId=$envVarId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListParams.kt index 3756de40..d8453ca7 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListParams.kt @@ -2,192 +2,217 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -import com.fasterxml.jackson.annotation.JsonCreator -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all env_vars. The env_vars are sorted by creation date, with the most recently-created + * env_vars coming first + */ class EnvVarListParams -constructor( +private constructor( private val envVarName: String?, private val ids: Ids?, private val limit: Long?, private val objectId: String?, - private val objectType: ObjectType?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val objectType: EnvVarObjectType?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + /** Name of the env_var to search for */ fun envVarName(): String? = envVarName + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** The id of the object the environment variable is scoped for */ fun objectId(): String? = objectId - fun objectType(): ObjectType? = objectType - - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.envVarName?.let { params.put("env_var_name", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.objectId?.let { params.put("object_id", listOf(it.toString())) } - this.objectType?.let { params.put("object_type", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders + /** The type of the object the environment variable is scoped for */ + fun objectType(): EnvVarObjectType? = objectType - fun _additionalQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is EnvVarListParams && - this.envVarName == other.envVarName && - this.ids == other.ids && - this.limit == other.limit && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - envVarName, - ids, - limit, - objectId, - objectType, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "EnvVarListParams{envVarName=$envVarName, ids=$ids, limit=$limit, objectId=$objectId, objectType=$objectType, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): EnvVarListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [EnvVarListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [EnvVarListParams]. */ + class Builder internal constructor() { private var envVarName: String? = null private var ids: Ids? = null private var limit: Long? = null private var objectId: String? = null - private var objectType: ObjectType? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var objectType: EnvVarObjectType? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(envVarListParams: EnvVarListParams) = apply { - this.envVarName = envVarListParams.envVarName - this.ids = envVarListParams.ids - this.limit = envVarListParams.limit - this.objectId = envVarListParams.objectId - this.objectType = envVarListParams.objectType - additionalQueryParams(envVarListParams.additionalQueryParams) - additionalHeaders(envVarListParams.additionalHeaders) + envVarName = envVarListParams.envVarName + ids = envVarListParams.ids + limit = envVarListParams.limit + objectId = envVarListParams.objectId + objectType = envVarListParams.objectType + additionalHeaders = envVarListParams.additionalHeaders.toBuilder() + additionalQueryParams = envVarListParams.additionalQueryParams.toBuilder() } /** Name of the env_var to search for */ - fun envVarName(envVarName: String) = apply { this.envVarName = envVarName } + fun envVarName(envVarName: String?) = apply { this.envVarName = envVarName } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** The id of the object the environment variable is scoped for */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun objectId(objectId: String?) = apply { this.objectId = objectId } /** The type of the object the environment variable is scoped for */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun objectType(objectType: EnvVarObjectType?) = apply { this.objectType = objectType } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + 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 putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [EnvVarListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): EnvVarListParams = EnvVarListParams( envVarName, @@ -195,22 +220,45 @@ constructor( limit, objectId, objectType, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + envVarName?.let { put("env_var_name", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + objectId?.let { put("object_id", it) } + objectType?.let { put("object_type", it.toString()) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -223,156 +271,72 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } - } - - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } - } - - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } } } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val FUNCTION = ObjectType(JsonField.of("function")) - - fun of(value: String) = ObjectType(JsonField.of(value)) - } - - enum class Known { - ORGANIZATION, - PROJECT, - FUNCTION, - } - - enum class Value { - ORGANIZATION, - PROJECT, - FUNCTION, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - FUNCTION -> Value.FUNCTION - else -> Value._UNKNOWN - } + return other is EnvVarListParams && + envVarName == other.envVarName && + ids == other.ids && + limit == other.limit && + objectId == other.objectId && + objectType == other.objectType && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - FUNCTION -> Known.FUNCTION - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } + override fun hashCode(): Int = + Objects.hash( + envVarName, + ids, + limit, + objectId, + objectType, + additionalHeaders, + additionalQueryParams, + ) - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "EnvVarListParams{envVarName=$envVarName, ids=$ids, limit=$limit, objectId=$objectId, objectType=$objectType, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListResponse.kt index e5717114..1741f829 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarListResponse.kt @@ -6,106 +6,184 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = EnvVarListResponse.Builder::class) -@NoAutoDetect class EnvVarListResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val objects: JsonField>, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** A list of env_var objects */ + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of env_var objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") - /** A list of env_var objects */ - @JsonProperty("objects") @ExcludeMissing fun _objects() = objects + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): EnvVarListResponse = apply { - if (!validated) { - objects().forEach { it.validate() } - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is EnvVarListResponse && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(objects, additionalProperties) - } - return hashCode - } - - override fun toString() = - "EnvVarListResponse{objects=$objects, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [EnvVarListResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [EnvVarListResponse]. */ + class Builder internal constructor() { - private var objects: JsonField> = JsonMissing.of() + private var objects: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(envVarListResponse: EnvVarListResponse) = apply { - this.objects = envVarListResponse.objects - additionalProperties(envVarListResponse.additionalProperties) + objects = envVarListResponse.objects.map { it.toMutableList() } + additionalProperties = envVarListResponse.additionalProperties.toMutableMap() } /** A list of env_var objects */ fun objects(objects: List) = objects(JsonField.of(objects)) - /** A list of env_var objects */ - @JsonProperty("objects") - @ExcludeMissing - fun objects(objects: JsonField>) = apply { this.objects = objects } + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [EnvVar] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: EnvVar) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [EnvVarListResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): EnvVarListResponse = EnvVarListResponse( - objects.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable() + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): EnvVarListResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is EnvVarListResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "EnvVarListResponse{objects=$objects, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarObjectType.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarObjectType.kt new file mode 100644 index 00000000..81da84bf --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarObjectType.kt @@ -0,0 +1,141 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Enum +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.errors.BraintrustInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator + +/** The type of the object the environment variable is scoped for */ +class EnvVarObjectType @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 { + + val ORGANIZATION = of("organization") + + val PROJECT = of("project") + + val FUNCTION = of("function") + + fun of(value: String) = EnvVarObjectType(JsonField.of(value)) + } + + /** An enum containing [EnvVarObjectType]'s known values. */ + enum class Known { + ORGANIZATION, + PROJECT, + FUNCTION, + } + + /** + * An enum containing [EnvVarObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [EnvVarObjectType] 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 { + ORGANIZATION, + PROJECT, + FUNCTION, + /** + * An enum member indicating that [EnvVarObjectType] 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) { + ORGANIZATION -> Value.ORGANIZATION + PROJECT -> Value.PROJECT + FUNCTION -> Value.FUNCTION + 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + ORGANIZATION -> Known.ORGANIZATION + PROJECT -> Known.PROJECT + FUNCTION -> Known.FUNCTION + else -> throw BraintrustInvalidDataException("Unknown EnvVarObjectType: $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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): EnvVarObjectType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + 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 EnvVarObjectType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarReplaceParams.kt index 5b1bfdae..f9cf95e5 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarReplaceParams.kt @@ -5,358 +5,666 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create or replace env_var. If there is an existing env_var with the same name as the one + * specified in the request, will replace the existing env_var with the provided fields + */ class EnvVarReplaceParams -constructor( - private val name: String, - private val objectId: String, - private val objectType: ObjectType, - private val value: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun objectId(): String = objectId - - fun objectType(): ObjectType = objectType - - fun value(): String? = value - - internal fun getBody(): EnvVarReplaceBody { - return EnvVarReplaceBody( - name, - objectId, - objectType, - value, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * The name of the environment variable + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * The id of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() + + /** + * The type of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = body.objectType() + + /** + * The value of the environment variable. Will be encrypted at rest. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun value(): String? = body.value() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _value(): JsonField = body._value() + + 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 [EnvVarReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [EnvVarReplaceParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = EnvVarReplaceBody.Builder::class) - @NoAutoDetect - class EnvVarReplaceBody - internal constructor( - private val name: String?, - private val objectId: String?, - private val objectType: ObjectType?, - private val value: String?, - private val additionalProperties: Map, - ) { + internal fun from(envVarReplaceParams: EnvVarReplaceParams) = apply { + body = envVarReplaceParams.body.toBuilder() + additionalHeaders = envVarReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = envVarReplaceParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [objectId] + * - [objectType] + * - [value] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** The name of the environment variable */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The id of the object the environment variable is scoped for */ - @JsonProperty("object_id") fun objectId(): String? = objectId + fun objectId(objectId: String) = apply { body.objectId(objectId) } + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } /** The type of the object the environment variable is scoped for */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + fun objectType(objectType: ObjectType) = apply { body.objectType(objectType) } + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } /** The value of the environment variable. Will be encrypted at rest. */ - @JsonProperty("value") fun value(): String? = value + fun value(value: String?) = apply { body.value(value) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun value(value: JsonField) = apply { body.value(value) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is EnvVarReplaceBody && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.value == other.value && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - objectId, - objectType, - value, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "EnvVarReplaceBody{name=$name, objectId=$objectId, objectType=$objectType, value=$value, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var value: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(envVarReplaceBody: EnvVarReplaceBody) = apply { - this.name = envVarReplaceBody.name - this.objectId = envVarReplaceBody.objectId - this.objectType = envVarReplaceBody.objectType - this.value = envVarReplaceBody.value - additionalProperties(envVarReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** The name of the environment variable */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** The id of the object the environment variable is scoped for */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The type of the object the environment variable is scoped for */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The value of the environment variable. Will be encrypted at rest. */ - @JsonProperty("value") fun value(value: String) = apply { this.value = value } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): EnvVarReplaceBody = - EnvVarReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - value, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is EnvVarReplaceParams && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.value == other.value && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [EnvVarReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EnvVarReplaceParams = + EnvVarReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - objectId, - objectType, - value, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "EnvVarReplaceParams{name=$name, objectId=$objectId, objectType=$objectType, value=$value, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val objectId: JsonField, + private val objectType: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this(name, objectId, objectType, value, mutableMapOf()) + + /** + * The name of the environment variable + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * The id of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + + /** + * The type of the object the environment variable is scoped for + * + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = objectType.getRequired("object_type") + + /** + * The value of the environment variable. Will be encrypted at rest. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun value(): String? = value.getNullable("value") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - @NoAutoDetect - class Builder { + fun toBuilder() = Builder().from(this) - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var value: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + companion object { - internal fun from(envVarReplaceParams: EnvVarReplaceParams) = apply { - this.name = envVarReplaceParams.name - this.objectId = envVarReplaceParams.objectId - this.objectType = envVarReplaceParams.objectType - this.value = envVarReplaceParams.value - additionalQueryParams(envVarReplaceParams.additionalQueryParams) - additionalHeaders(envVarReplaceParams.additionalHeaders) - additionalBodyProperties(envVarReplaceParams.additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - /** The name of the environment variable */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** The id of the object the environment variable is scoped for */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + private var name: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** The type of the object the environment variable is scoped for */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + internal fun from(body: Body) = apply { + name = body.name + objectId = body.objectId + objectType = body.objectType + value = body.value + additionalProperties = body.additionalProperties.toMutableMap() + } - /** The value of the environment variable. Will be encrypted at rest. */ - fun value(value: String) = apply { this.value = value } + /** The name of the environment variable */ + fun name(name: String) = name(JsonField.of(name)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** The id of the object the environment variable is scoped for */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** The type of the object the environment variable is scoped for */ + fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** The value of the environment variable. Will be encrypted at rest. */ + fun value(value: String?) = value(JsonField.ofNullable(value)) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun value(value: JsonField) = apply { this.value = value } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + value, + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply } - fun build(): EnvVarReplaceParams = - EnvVarReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - value, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + name() + objectId() + objectType().validate() + value() + validated = true + } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (value.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is ObjectType && this.value == other.value + return other is Body && + name == other.name && + objectId == other.objectId && + objectType == other.objectType && + value == other.value && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash(name, objectId, objectType, value, additionalProperties) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, objectId=$objectId, objectType=$objectType, value=$value, additionalProperties=$additionalProperties}" + } + + /** The type of the object the environment variable is scoped for */ + class ObjectType @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 { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + val ORGANIZATION = of("organization") - val PROJECT = ObjectType(JsonField.of("project")) + val PROJECT = of("project") - val FUNCTION = ObjectType(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = ObjectType(JsonField.of(value)) } + /** An enum containing [ObjectType]'s known values. */ enum class Known { ORGANIZATION, PROJECT, FUNCTION, } + /** + * An enum containing [ObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ObjectType] 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 { ORGANIZATION, PROJECT, FUNCTION, + /** + * An enum member indicating that [ObjectType] 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) { ORGANIZATION -> Value.ORGANIZATION @@ -365,6 +673,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { ORGANIZATION -> Known.ORGANIZATION @@ -373,6 +690,71 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ObjectType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ObjectType && 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 EnvVarReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "EnvVarReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParams.kt index f611220c..648496b1 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParams.kt @@ -2,125 +2,184 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get an env_var object by its id */ class EnvVarRetrieveParams -constructor( - private val envVarId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val envVarId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun envVarId(): String = envVarId + /** EnvVar id */ + fun envVarId(): String? = envVarId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> envVarId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): EnvVarRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [EnvVarRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [EnvVarRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var envVarId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(envVarRetrieveParams: EnvVarRetrieveParams) = apply { + envVarId = envVarRetrieveParams.envVarId + additionalHeaders = envVarRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = envVarRetrieveParams.additionalQueryParams.toBuilder() } - return other is EnvVarRetrieveParams && - this.envVarId == other.envVarId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** EnvVar id */ + fun envVarId(envVarId: String?) = apply { this.envVarId = envVarId } - override fun hashCode(): Int { - return Objects.hash( - envVarId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "EnvVarRetrieveParams{envVarId=$envVarId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var envVarId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(envVarRetrieveParams: EnvVarRetrieveParams) = apply { - this.envVarId = envVarRetrieveParams.envVarId - additionalQueryParams(envVarRetrieveParams.additionalQueryParams) - additionalHeaders(envVarRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** EnvVar id */ - fun envVarId(envVarId: String) = apply { this.envVarId = envVarId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [EnvVarRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): EnvVarRetrieveParams = - EnvVarRetrieveParams( - checkNotNull(envVarId) { "`envVarId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) + EnvVarRetrieveParams(envVarId, additionalHeaders.build(), additionalQueryParams.build()) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> envVarId ?: "" + 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 EnvVarRetrieveParams && + envVarId == other.envVarId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(envVarId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "EnvVarRetrieveParams{envVarId=$envVarId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarUpdateParams.kt index 2c28a7e0..e8f941fb 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EnvVarUpdateParams.kt @@ -3,277 +3,494 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update an env_var object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class EnvVarUpdateParams -constructor( - private val envVarId: String, - private val name: String, - private val value: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun envVarId(): String = envVarId - - fun name(): String = name - - fun value(): String? = value - - internal fun getBody(): EnvVarUpdateBody { - return EnvVarUpdateBody( - name, - value, - additionalBodyProperties, - ) - } +private constructor( + private val envVarId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** EnvVar id */ + fun envVarId(): String? = envVarId + + /** + * The name of the environment variable + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * The value of the environment variable. Will be encrypted at rest. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun value(): String? = body.value() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _value(): JsonField = body._value() + + 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 - internal fun getQueryParams(): Map> = additionalQueryParams + fun toBuilder() = Builder().from(this) - internal fun getHeaders(): Map> = additionalHeaders + companion object { - fun getPathParam(index: Int): String { - return when (index) { - 0 -> envVarId - else -> "" - } + /** + * Returns a mutable builder for constructing an instance of [EnvVarUpdateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - @JsonDeserialize(builder = EnvVarUpdateBody.Builder::class) - @NoAutoDetect - class EnvVarUpdateBody - internal constructor( - private val name: String?, - private val value: String?, - private val additionalProperties: Map, - ) { + /** A builder for [EnvVarUpdateParams]. */ + class Builder internal constructor() { + + private var envVarId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var hashCode: Int = 0 + internal fun from(envVarUpdateParams: EnvVarUpdateParams) = apply { + envVarId = envVarUpdateParams.envVarId + body = envVarUpdateParams.body.toBuilder() + additionalHeaders = envVarUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = envVarUpdateParams.additionalQueryParams.toBuilder() + } + + /** EnvVar id */ + fun envVarId(envVarId: String?) = apply { this.envVarId = envVarId } + + /** + * 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: + * - [name] + * - [value] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** The name of the environment variable */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The value of the environment variable. Will be encrypted at rest. */ - @JsonProperty("value") fun value(): String? = value + fun value(value: String?) = apply { body.value(value) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun value(value: JsonField) = apply { body.value(value) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is EnvVarUpdateBody && - this.name == other.name && - this.value == other.value && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - value, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "EnvVarUpdateBody{name=$name, value=$value, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var name: String? = null - private var value: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(envVarUpdateBody: EnvVarUpdateBody) = apply { - this.name = envVarUpdateBody.name - this.value = envVarUpdateBody.value - additionalProperties(envVarUpdateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** The name of the environment variable */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The value of the environment variable. Will be encrypted at rest. */ - @JsonProperty("value") fun value(value: String) = apply { this.value = value } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun build(): EnvVarUpdateBody = - EnvVarUpdateBody( - checkNotNull(name) { "`name` is required but was not set" }, - value, - additionalProperties.toUnmodifiable(), - ) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - return other is EnvVarUpdateParams && - this.envVarId == other.envVarId && - this.name == other.name && - this.value == other.value && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun hashCode(): Int { - return Objects.hash( - envVarId, - name, - value, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - override fun toString() = - "EnvVarUpdateParams{envVarId=$envVarId, name=$name, value=$value, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun toBuilder() = Builder().from(this) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - companion object { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun builder() = Builder() - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - @NoAutoDetect - class Builder { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - private var envVarId: String? = null - private var name: String? = null - private var value: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + /** + * Returns an immutable instance of [EnvVarUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EnvVarUpdateParams = + EnvVarUpdateParams( + envVarId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } - internal fun from(envVarUpdateParams: EnvVarUpdateParams) = apply { - this.envVarId = envVarUpdateParams.envVarId - this.name = envVarUpdateParams.name - this.value = envVarUpdateParams.value - additionalQueryParams(envVarUpdateParams.additionalQueryParams) - additionalHeaders(envVarUpdateParams.additionalHeaders) - additionalBodyProperties(envVarUpdateParams.additionalBodyProperties) + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> envVarId ?: "" + else -> "" } - /** EnvVar id */ - fun envVarId(envVarId: String) = apply { this.envVarId = envVarId } + override fun _headers(): Headers = additionalHeaders - /** The name of the environment variable */ - fun name(name: String) = apply { this.name = name } + override fun _queryParams(): QueryParams = additionalQueryParams - /** The value of the environment variable. Will be encrypted at rest. */ - fun value(value: String) = apply { this.value = value } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val value: JsonField, + private val additionalProperties: MutableMap, + ) { - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this(name, value, mutableMapOf()) + + /** + * The name of the environment variable + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * The value of the environment variable. Will be encrypted at rest. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun value(): String? = value.getNullable("value") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + companion object { - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + private var name: JsonField? = null + private var value: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + internal fun from(body: Body) = apply { + name = body.name + value = body.value + additionalProperties = body.additionalProperties.toMutableMap() + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** The name of the environment variable */ + fun name(name: String) = name(JsonField.of(name)) - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** The value of the environment variable. Will be encrypted at rest. */ + fun value(value: String?) = value(JsonField.ofNullable(value)) + + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun value(value: JsonField) = apply { this.value = value } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body(checkRequired("name", name), value, additionalProperties.toMutableMap()) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + value() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): EnvVarUpdateParams = - EnvVarUpdateParams( - checkNotNull(envVarId) { "`envVarId` is required but was not set" }, - checkNotNull(name) { "`name` is required but was not set" }, - value, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (if (value.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + value == other.value && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, value, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, value=$value, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is EnvVarUpdateParams && + envVarId == other.envVarId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(envVarId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "EnvVarUpdateParams{envVarId=$envVarId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EvalCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EvalCreateParams.kt index b90ae621..bd3c8218 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EvalCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/EvalCreateParams.kt @@ -9,11 +9,15 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -25,765 +29,4684 @@ 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 +/** + * Launch an evaluation. This is the API-equivalent of the `Eval` function that is built into the + * Braintrust SDK. In the Eval API, you provide pointers to a dataset, task function, and scoring + * functions. The API will then run the evaluation, create an experiment, and return the results + * along with a link to the experiment. To learn more about evals, see the + * [Evals guide](https://www.braintrust.dev/docs/guides/evals). + */ class EvalCreateParams -constructor( - private val data: Data, - private val projectId: String, - private val scores: List, - private val task: Task, - private val experimentName: String?, - private val metadata: Metadata?, - private val stream: Boolean?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun data(): Data = data - - fun projectId(): String = projectId - - fun scores(): List = scores - - fun task(): Task = task - - fun experimentName(): String? = experimentName - - fun metadata(): Metadata? = metadata - - fun stream(): Boolean? = stream - - internal fun getBody(): EvalCreateBody { - return EvalCreateBody( - data, - projectId, - scores, - task, - experimentName, - metadata, - stream, - additionalBodyProperties, - ) - } - - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = EvalCreateBody.Builder::class) - @NoAutoDetect - class EvalCreateBody - internal constructor( - private val data: Data?, - private val projectId: String?, - private val scores: List?, - private val task: Task?, - private val experimentName: String?, - private val metadata: Metadata?, - private val stream: Boolean?, - private val additionalProperties: Map, - ) { - - private var hashCode: Int = 0 - - /** The dataset to use */ - @JsonProperty("data") fun data(): Data? = data + /** + * The dataset to use + * + * @throws BraintrustInvalidDataException 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 = body.data() - /** Unique identifier for the project to run the eval in */ - @JsonProperty("project_id") fun projectId(): String? = projectId + /** + * Unique identifier for the project to run the eval in + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() - /** The functions to score the eval on */ - @JsonProperty("scores") fun scores(): List? = scores + /** + * The functions to score the eval on + * + * @throws BraintrustInvalidDataException 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 scores(): List = body.scores() - /** The function to evaluate */ - @JsonProperty("task") fun task(): Task? = task + /** + * The function to evaluate + * + * @throws BraintrustInvalidDataException 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 task(): Task = body.task() - /** - * An optional name for the experiment created by this eval. If it conflicts with an - * existing experiment, it will be suffixed with a unique identifier. - */ - @JsonProperty("experiment_name") fun experimentName(): String? = experimentName + /** + * An optional experiment id to use as a base. If specified, the new experiment will be + * summarized and compared to this experiment. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baseExperimentId(): String? = body.baseExperimentId() - /** - * Optional experiment-level metadata to store about the evaluation. You can later use this - * to slice & dice across experiments. - */ - @JsonProperty("metadata") fun metadata(): Metadata? = metadata + /** + * An optional experiment name to use as a base. If specified, the new experiment will be + * summarized and compared to this experiment. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baseExperimentName(): String? = body.baseExperimentName() - /** - * Whether to stream the results of the eval. If true, the request will return two events: - * one to indicate the experiment has started, and another upon completion. If false, the - * request will return the evaluation's summary upon completion. - */ - @JsonProperty("stream") fun stream(): Boolean? = stream + /** + * An optional name for the experiment created by this eval. If it conflicts with an existing + * experiment, it will be suffixed with a unique identifier. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun experimentName(): String? = body.experimentName() - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Optional settings for collecting git metadata. By default, will collect all git metadata + * fields allowed in org-level settings. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun gitMetadataSettings(): GitMetadataSettings? = body.gitMetadataSettings() - fun toBuilder() = Builder().from(this) + /** + * Whether the experiment should be public. Defaults to false. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun isPublic(): Boolean? = body.isPublic() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * The maximum number of tasks/scorers that will be run concurrently. Defaults to undefined, in + * which case there is no max concurrency. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun maxConcurrency(): Double? = body.maxConcurrency() - return other is EvalCreateBody && - this.data == other.data && - this.projectId == other.projectId && - this.scores == other.scores && - this.task == other.task && - this.experimentName == other.experimentName && - this.metadata == other.metadata && - this.stream == other.stream && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - data, - projectId, - scores, - task, - experimentName, - metadata, - stream, - additionalProperties, - ) - } - return hashCode - } + /** + * Optional experiment-level metadata to store about the evaluation. You can later use this to + * slice & dice across experiments. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() - override fun toString() = - "EvalCreateBody{data=$data, projectId=$projectId, scores=$scores, task=$task, experimentName=$experimentName, metadata=$metadata, stream=$stream, additionalProperties=$additionalProperties}" + /** + * Options for tracing the evaluation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun parent(): Parent? = body.parent() - companion object { + /** + * Metadata about the state of the repo when the experiment was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun repoInfo(): RepoInfo? = body.repoInfo() - fun builder() = Builder() - } + /** + * Whether to stream the results of the eval. If true, the request will return two events: one + * to indicate the experiment has started, and another upon completion. If false, the request + * will return the evaluation's summary upon completion. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun stream(): Boolean? = body.stream() - class Builder { + /** + * The maximum duration, in milliseconds, to run the evaluation. Defaults to undefined, in which + * case there is no timeout. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun timeout(): Double? = body.timeout() - private var data: Data? = null - private var projectId: String? = null - private var scores: List? = null - private var task: Task? = null - private var experimentName: String? = null - private var metadata: Metadata? = null - private var stream: Boolean? = null - private var additionalProperties: MutableMap = mutableMapOf() + /** + * The number of times to run the evaluator per input. This is useful for evaluating + * applications that have non-deterministic behavior and gives you both a stronger aggregate + * measure and a sense of the variance in the results. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun trialCount(): Double? = body.trialCount() - internal fun from(evalCreateBody: EvalCreateBody) = apply { - this.data = evalCreateBody.data - this.projectId = evalCreateBody.projectId - this.scores = evalCreateBody.scores - this.task = evalCreateBody.task - this.experimentName = evalCreateBody.experimentName - this.metadata = evalCreateBody.metadata - this.stream = evalCreateBody.stream - additionalProperties(evalCreateBody.additionalProperties) - } + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _data(): JsonField = body._data() - /** The dataset to use */ - @JsonProperty("data") fun data(data: Data) = apply { this.data = data } + /** + * 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() - /** Unique identifier for the project to run the eval in */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + /** + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _scores(): JsonField> = body._scores() - /** The functions to score the eval on */ - @JsonProperty("scores") fun scores(scores: List) = apply { this.scores = scores } + /** + * Returns the raw JSON value of [task]. + * + * Unlike [task], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _task(): JsonField = body._task() - /** The function to evaluate */ - @JsonProperty("task") fun task(task: Task) = apply { this.task = task } + /** + * Returns the raw JSON value of [baseExperimentId]. + * + * Unlike [baseExperimentId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _baseExperimentId(): JsonField = body._baseExperimentId() - /** - * An optional name for the experiment created by this eval. If it conflicts with an - * existing experiment, it will be suffixed with a unique identifier. - */ - @JsonProperty("experiment_name") - fun experimentName(experimentName: String) = apply { - this.experimentName = experimentName - } + /** + * Returns the raw JSON value of [baseExperimentName]. + * + * Unlike [baseExperimentName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _baseExperimentName(): JsonField = body._baseExperimentName() - /** - * Optional experiment-level metadata to store about the evaluation. You can later use - * this to slice & dice across experiments. - */ - @JsonProperty("metadata") - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + /** + * Returns the raw JSON value of [experimentName]. + * + * Unlike [experimentName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _experimentName(): JsonField = body._experimentName() - /** - * Whether to stream the results of the eval. If true, the request will return two - * events: one to indicate the experiment has started, and another upon completion. If - * false, the request will return the evaluation's summary upon completion. - */ - @JsonProperty("stream") fun stream(stream: Boolean) = apply { this.stream = stream } + /** + * Returns the raw JSON value of [gitMetadataSettings]. + * + * Unlike [gitMetadataSettings], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _gitMetadataSettings(): JsonField = body._gitMetadataSettings() - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + /** + * Returns the raw JSON value of [isPublic]. + * + * Unlike [isPublic], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _isPublic(): JsonField = body._isPublic() - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + /** + * Returns the raw JSON value of [maxConcurrency]. + * + * Unlike [maxConcurrency], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _maxConcurrency(): JsonField = body._maxConcurrency() - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() - fun build(): EvalCreateBody = - EvalCreateBody( - checkNotNull(data) { "`data` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(scores) { "`scores` is required but was not set" } - .toUnmodifiable(), - checkNotNull(task) { "`task` is required but was not set" }, - experimentName, - metadata, - stream, - additionalProperties.toUnmodifiable(), - ) - } - } + /** + * Returns the raw JSON value of [parent]. + * + * Unlike [parent], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _parent(): JsonField = body._parent() - fun _additionalQueryParams(): Map> = additionalQueryParams + /** + * Returns the raw JSON value of [repoInfo]. + * + * Unlike [repoInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _repoInfo(): JsonField = body._repoInfo() - fun _additionalHeaders(): Map> = additionalHeaders + /** + * Returns the raw JSON value of [stream]. + * + * Unlike [stream], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _stream(): JsonField = body._stream() - fun _additionalBodyProperties(): Map = additionalBodyProperties + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _timeout(): JsonField = body._timeout() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [trialCount]. + * + * Unlike [trialCount], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _trialCount(): JsonField = body._trialCount() - return other is EvalCreateParams && - this.data == other.data && - this.projectId == other.projectId && - this.scores == other.scores && - this.task == other.task && - this.experimentName == other.experimentName && - this.metadata == other.metadata && - this.stream == other.stream && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun _additionalBodyProperties(): Map = body._additionalProperties() - override fun hashCode(): Int { - return Objects.hash( - data, - projectId, - scores, - task, - experimentName, - metadata, - stream, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "EvalCreateParams{data=$data, projectId=$projectId, scores=$scores, task=$task, experimentName=$experimentName, metadata=$metadata, stream=$stream, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + /** 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 [EvalCreateParams]. + * + * The following fields are required: + * ```kotlin + * .data() + * .projectId() + * .scores() + * .task() + * ``` + */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [EvalCreateParams]. */ + class Builder internal constructor() { - private var data: Data? = null - private var projectId: String? = null - private var scores: MutableList = mutableListOf() - private var task: Task? = null - private var experimentName: String? = null - private var metadata: Metadata? = null - private var stream: Boolean? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(evalCreateParams: EvalCreateParams) = apply { - this.data = evalCreateParams.data - this.projectId = evalCreateParams.projectId - this.scores(evalCreateParams.scores) - this.task = evalCreateParams.task - this.experimentName = evalCreateParams.experimentName - this.metadata = evalCreateParams.metadata - this.stream = evalCreateParams.stream - additionalQueryParams(evalCreateParams.additionalQueryParams) - additionalHeaders(evalCreateParams.additionalHeaders) - additionalBodyProperties(evalCreateParams.additionalBodyProperties) + body = evalCreateParams.body.toBuilder() + additionalHeaders = evalCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = evalCreateParams.additionalQueryParams.toBuilder() } - /** The dataset to use */ - fun data(data: Data) = apply { this.data = data } + /** + * 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: + * - [data] + * - [projectId] + * - [scores] + * - [task] + * - [baseExperimentId] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** The dataset to use */ - fun data(datasetId: Data.DatasetId) = apply { this.data = Data.ofDatasetId(datasetId) } + fun data(data: Data) = apply { body.data(data) } - /** The dataset to use */ + /** + * 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 { body.data(data) } + + /** Alias for calling [data] with `Data.ofDatasetId(datasetId)`. */ + fun data(datasetId: Data.DatasetId) = apply { body.data(datasetId) } + + /** Alias for calling [data] with `Data.ofProjectDatasetName(projectDatasetName)`. */ fun data(projectDatasetName: Data.ProjectDatasetName) = apply { - this.data = Data.ofProjectDatasetName(projectDatasetName) + body.data(projectDatasetName) } + /** Alias for calling [data] with `Data.ofDatasetRows(datasetRows)`. */ + fun data(datasetRows: Data.DatasetRows) = apply { body.data(datasetRows) } + /** Unique identifier for the project to run the eval in */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String) = apply { body.projectId(projectId) } - /** The functions to score the eval on */ - fun scores(scores: List) = apply { - this.scores.clear() - this.scores.addAll(scores) - } + /** + * 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) } /** The functions to score the eval on */ - fun addScore(score: Score) = apply { this.scores.add(score) } + fun scores(scores: List) = apply { body.scores(scores) } - /** The function to evaluate */ - fun task(task: Task) = apply { this.task = task } + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun scores(scores: JsonField>) = apply { body.scores(scores) } - /** The function to evaluate */ - fun task(functionId: Task.FunctionId) = apply { this.task = Task.ofFunctionId(functionId) } + /** + * Adds a single [Score] to [scores]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addScore(score: Score) = apply { body.addScore(score) } - /** The function to evaluate */ - fun task(projectSlug: Task.ProjectSlug) = apply { - this.task = Task.ofProjectSlug(projectSlug) - } + /** Alias for calling [addScore] with `Score.ofFunctionId(functionId)`. */ + fun addScore(functionId: Score.FunctionId) = apply { body.addScore(functionId) } - /** The function to evaluate */ - fun task(globalFunction: Task.GlobalFunction) = apply { - this.task = Task.ofGlobalFunction(globalFunction) - } + /** Alias for calling [addScore] with `Score.ofProjectSlug(projectSlug)`. */ + fun addScore(projectSlug: Score.ProjectSlug) = apply { body.addScore(projectSlug) } - /** The function to evaluate */ - fun task(promptSessionId: Task.PromptSessionId) = apply { - this.task = Task.ofPromptSessionId(promptSessionId) + /** Alias for calling [addScore] with `Score.ofGlobalFunction(globalFunction)`. */ + fun addScore(globalFunction: Score.GlobalFunction) = apply { body.addScore(globalFunction) } + + /** Alias for calling [addScore] with `Score.ofPromptSessionId(promptSessionId)`. */ + fun addScore(promptSessionId: Score.PromptSessionId) = apply { + body.addScore(promptSessionId) } - /** The function to evaluate */ - fun task(inlineCode: Task.InlineCode) = apply { this.task = Task.ofInlineCode(inlineCode) } + /** Alias for calling [addScore] with `Score.ofInlineCode(inlineCode)`. */ + fun addScore(inlineCode: Score.InlineCode) = apply { body.addScore(inlineCode) } + + /** Alias for calling [addScore] with `Score.ofInlinePrompt(inlinePrompt)`. */ + fun addScore(inlinePrompt: Score.InlinePrompt) = apply { body.addScore(inlinePrompt) } /** The function to evaluate */ - fun task(inlinePrompt: Task.InlinePrompt) = apply { - this.task = Task.ofInlinePrompt(inlinePrompt) - } + fun task(task: Task) = apply { body.task(task) } /** - * An optional name for the experiment created by this eval. If it conflicts with an - * existing experiment, it will be suffixed with a unique identifier. + * Sets [Builder.task] to an arbitrary JSON value. + * + * You should usually call [Builder.task] with a well-typed [Task] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun experimentName(experimentName: String) = apply { this.experimentName = experimentName } + fun task(task: JsonField) = apply { body.task(task) } + + /** Alias for calling [task] with `Task.ofFunctionId(functionId)`. */ + fun task(functionId: Task.FunctionId) = apply { body.task(functionId) } + + /** Alias for calling [task] with `Task.ofProjectSlug(projectSlug)`. */ + fun task(projectSlug: Task.ProjectSlug) = apply { body.task(projectSlug) } + + /** Alias for calling [task] with `Task.ofGlobalFunction(globalFunction)`. */ + fun task(globalFunction: Task.GlobalFunction) = apply { body.task(globalFunction) } + + /** Alias for calling [task] with `Task.ofPromptSessionId(promptSessionId)`. */ + fun task(promptSessionId: Task.PromptSessionId) = apply { body.task(promptSessionId) } + + /** Alias for calling [task] with `Task.ofInlineCode(inlineCode)`. */ + fun task(inlineCode: Task.InlineCode) = apply { body.task(inlineCode) } + + /** Alias for calling [task] with `Task.ofInlinePrompt(inlinePrompt)`. */ + fun task(inlinePrompt: Task.InlinePrompt) = apply { body.task(inlinePrompt) } /** - * Optional experiment-level metadata to store about the evaluation. You can later use this - * to slice & dice across experiments. + * An optional experiment id to use as a base. If specified, the new experiment will be + * summarized and compared to this experiment. */ - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + fun baseExperimentId(baseExperimentId: String?) = apply { + body.baseExperimentId(baseExperimentId) + } /** - * Whether to stream the results of the eval. If true, the request will return two events: - * one to indicate the experiment has started, and another upon completion. If false, the - * request will return the evaluation's summary upon completion. + * Sets [Builder.baseExperimentId] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExperimentId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun stream(stream: Boolean) = apply { this.stream = stream } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun baseExperimentId(baseExperimentId: JsonField) = apply { + body.baseExperimentId(baseExperimentId) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + /** + * An optional experiment name to use as a base. If specified, the new experiment will be + * summarized and compared to this experiment. + */ + fun baseExperimentName(baseExperimentName: String?) = apply { + body.baseExperimentName(baseExperimentName) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + /** + * Sets [Builder.baseExperimentName] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExperimentName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun baseExperimentName(baseExperimentName: JsonField) = apply { + body.baseExperimentName(baseExperimentName) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * An optional name for the experiment created by this eval. If it conflicts with an + * existing experiment, it will be suffixed with a unique identifier. + */ + fun experimentName(experimentName: String) = apply { body.experimentName(experimentName) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + /** + * Sets [Builder.experimentName] to an arbitrary JSON value. + * + * You should usually call [Builder.experimentName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun experimentName(experimentName: JsonField) = apply { + body.experimentName(experimentName) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + /** + * Optional settings for collecting git metadata. By default, will collect all git metadata + * fields allowed in org-level settings. + */ + fun gitMetadataSettings(gitMetadataSettings: GitMetadataSettings?) = apply { + body.gitMetadataSettings(gitMetadataSettings) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + /** + * Sets [Builder.gitMetadataSettings] to an arbitrary JSON value. + * + * You should usually call [Builder.gitMetadataSettings] with a well-typed + * [GitMetadataSettings] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun gitMetadataSettings(gitMetadataSettings: JsonField) = apply { + body.gitMetadataSettings(gitMetadataSettings) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** Whether the experiment should be public. Defaults to false. */ + fun isPublic(isPublic: Boolean?) = apply { body.isPublic(isPublic) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** + * Alias for [Builder.isPublic]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun isPublic(isPublic: Boolean) = isPublic(isPublic as Boolean?) - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** + * Sets [Builder.isPublic] to an arbitrary JSON value. + * + * You should usually call [Builder.isPublic] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun isPublic(isPublic: JsonField) = apply { body.isPublic(isPublic) } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + /** + * The maximum number of tasks/scorers that will be run concurrently. Defaults to undefined, + * in which case there is no max concurrency. + */ + fun maxConcurrency(maxConcurrency: Double?) = apply { body.maxConcurrency(maxConcurrency) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + /** + * Alias for [Builder.maxConcurrency]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun maxConcurrency(maxConcurrency: Double) = maxConcurrency(maxConcurrency as Double?) + + /** + * Sets [Builder.maxConcurrency] to an arbitrary JSON value. + * + * You should usually call [Builder.maxConcurrency] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxConcurrency(maxConcurrency: JsonField) = apply { + body.maxConcurrency(maxConcurrency) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + /** + * Optional experiment-level metadata to store about the evaluation. You can later use this + * to slice & dice across experiments. + */ + fun metadata(metadata: Metadata) = apply { body.metadata(metadata) } - fun build(): EvalCreateParams = - EvalCreateParams( - checkNotNull(data) { "`data` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(scores) { "`scores` is required but was not set" }.toUnmodifiable(), - checkNotNull(task) { "`task` is required but was not set" }, - experimentName, - metadata, - stream, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + /** + * 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 { body.metadata(metadata) } - @JsonDeserialize(using = Data.Deserializer::class) - @JsonSerialize(using = Data.Serializer::class) - class Data - private constructor( - private val datasetId: DatasetId? = null, - private val projectDatasetName: ProjectDatasetName? = null, - private val _json: JsonValue? = null, - ) { + /** Options for tracing the evaluation */ + fun parent(parent: Parent) = apply { body.parent(parent) } - private var validated: Boolean = false + /** + * Sets [Builder.parent] to an arbitrary JSON value. + * + * You should usually call [Builder.parent] with a well-typed [Parent] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun parent(parent: JsonField) = apply { body.parent(parent) } - /** Dataset id */ - fun datasetId(): DatasetId? = datasetId - /** Project and dataset name */ - fun projectDatasetName(): ProjectDatasetName? = projectDatasetName + /** Alias for calling [parent] with `Parent.ofSpanParentStruct(spanParentStruct)`. */ + fun parent(spanParentStruct: Parent.SpanParentStruct) = apply { + body.parent(spanParentStruct) + } - fun isDatasetId(): Boolean = datasetId != null + /** Alias for calling [parent] with `Parent.ofString(string)`. */ + fun parent(string: String) = apply { body.parent(string) } - fun isProjectDatasetName(): Boolean = projectDatasetName != null + /** Metadata about the state of the repo when the experiment was created */ + fun repoInfo(repoInfo: RepoInfo?) = apply { body.repoInfo(repoInfo) } - fun asDatasetId(): DatasetId = datasetId.getOrThrow("datasetId") + /** + * Sets [Builder.repoInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.repoInfo] with a well-typed [RepoInfo] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun repoInfo(repoInfo: JsonField) = apply { body.repoInfo(repoInfo) } - fun asProjectDatasetName(): ProjectDatasetName = - projectDatasetName.getOrThrow("projectDatasetName") + /** + * Whether to stream the results of the eval. If true, the request will return two events: + * one to indicate the experiment has started, and another upon completion. If false, the + * request will return the evaluation's summary upon completion. + */ + fun stream(stream: Boolean) = apply { body.stream(stream) } - fun _json(): JsonValue? = _json + /** + * Sets [Builder.stream] to an arbitrary JSON value. + * + * You should usually call [Builder.stream] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun stream(stream: JsonField) = apply { body.stream(stream) } - fun accept(visitor: Visitor): T { - return when { - datasetId != null -> visitor.visitDatasetId(datasetId) - projectDatasetName != null -> visitor.visitProjectDatasetName(projectDatasetName) - else -> visitor.unknown(_json) - } - } + /** + * The maximum duration, in milliseconds, to run the evaluation. Defaults to undefined, in + * which case there is no timeout. + */ + fun timeout(timeout: Double?) = apply { body.timeout(timeout) } - fun validate(): Data = apply { - if (!validated) { - if (datasetId == null && projectDatasetName == null) { - throw BraintrustInvalidDataException("Unknown Data: $_json") - } - datasetId?.validate() - projectDatasetName?.validate() - validated = true - } - } + /** + * Alias for [Builder.timeout]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun timeout(timeout: Double) = timeout(timeout as Double?) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * 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 { body.timeout(timeout) } - return other is Data && - this.datasetId == other.datasetId && - this.projectDatasetName == other.projectDatasetName - } + /** + * The number of times to run the evaluator per input. This is useful for evaluating + * applications that have non-deterministic behavior and gives you both a stronger aggregate + * measure and a sense of the variance in the results. + */ + fun trialCount(trialCount: Double?) = apply { body.trialCount(trialCount) } + + /** + * Alias for [Builder.trialCount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun trialCount(trialCount: Double) = trialCount(trialCount as Double?) + + /** + * Sets [Builder.trialCount] to an arbitrary JSON value. + * + * You should usually call [Builder.trialCount] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun trialCount(trialCount: JsonField) = apply { body.trialCount(trialCount) } - override fun hashCode(): Int { - return Objects.hash(datasetId, projectDatasetName) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) } - override fun toString(): String { - return when { - datasetId != null -> "Data{datasetId=$datasetId}" - projectDatasetName != null -> "Data{projectDatasetName=$projectDatasetName}" - _json != null -> "Data{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Data") - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - companion object { + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } - fun ofDatasetId(datasetId: DatasetId) = Data(datasetId = datasetId) + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - fun ofProjectDatasetName(projectDatasetName: ProjectDatasetName) = - Data(projectDatasetName = projectDatasetName) + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - interface Visitor { - - fun visitDatasetId(datasetId: DatasetId): T + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun visitProjectDatasetName(projectDatasetName: ProjectDatasetName): T + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Data: $json") - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Deserializer : BaseDeserializer(Data::class) { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - override fun ObjectCodec.deserialize(node: JsonNode): Data { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Data(datasetId = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Data(projectDatasetName = it, _json = json) - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - return Data(_json = json) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - class Serializer : BaseSerializer(Data::class) { + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - override fun serialize( - value: Data, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.datasetId != null -> generator.writeObject(value.datasetId) - value.projectDatasetName != null -> - generator.writeObject(value.projectDatasetName) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Data") - } - } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Dataset id */ - @JsonDeserialize(builder = DatasetId.Builder::class) - @NoAutoDetect - class DatasetId - private constructor( - private val datasetId: JsonField, - private val additionalProperties: Map, - ) { + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - private var validated: Boolean = false + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - private var hashCode: Int = 0 + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun datasetId(): String = datasetId.getRequired("dataset_id") + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonProperty("dataset_id") @ExcludeMissing fun _datasetId() = datasetId + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun validate(): DatasetId = apply { - if (!validated) { - datasetId() - validated = true - } - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - return other is DatasetId && - this.datasetId == other.datasetId && - this.additionalProperties == other.additionalProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(datasetId, additionalProperties) - } - return hashCode - } + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - override fun toString() = - "DatasetId{datasetId=$datasetId, additionalProperties=$additionalProperties}" + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - companion object { + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun builder() = Builder() + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - class Builder { + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - private var datasetId: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - internal fun from(datasetId: DatasetId) = apply { - this.datasetId = datasetId.datasetId - additionalProperties(datasetId.additionalProperties) - } + /** + * Returns an immutable instance of [EvalCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .data() + * .projectId() + * .scores() + * .task() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EvalCreateParams = + EvalCreateParams(body.build(), additionalHeaders.build(), additionalQueryParams.build()) + } - fun datasetId(datasetId: String) = datasetId(JsonField.of(datasetId)) + fun _body(): Body = body - @JsonProperty("dataset_id") - @ExcludeMissing - fun datasetId(datasetId: JsonField) = apply { this.datasetId = datasetId } + override fun _headers(): Headers = additionalHeaders - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val data: JsonField, + private val projectId: JsonField, + private val scores: JsonField>, + private val task: JsonField, + private val baseExperimentId: JsonField, + private val baseExperimentName: JsonField, + private val experimentName: JsonField, + private val gitMetadataSettings: JsonField, + private val isPublic: JsonField, + private val maxConcurrency: JsonField, + private val metadata: JsonField, + private val parent: JsonField, + private val repoInfo: JsonField, + private val stream: JsonField, + private val timeout: JsonField, + private val trialCount: JsonField, + private val additionalProperties: MutableMap, + ) { - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("scores") + @ExcludeMissing + scores: JsonField> = JsonMissing.of(), + @JsonProperty("task") @ExcludeMissing task: JsonField = JsonMissing.of(), + @JsonProperty("base_experiment_id") + @ExcludeMissing + baseExperimentId: JsonField = JsonMissing.of(), + @JsonProperty("base_experiment_name") + @ExcludeMissing + baseExperimentName: JsonField = JsonMissing.of(), + @JsonProperty("experiment_name") + @ExcludeMissing + experimentName: JsonField = JsonMissing.of(), + @JsonProperty("git_metadata_settings") + @ExcludeMissing + gitMetadataSettings: JsonField = JsonMissing.of(), + @JsonProperty("is_public") + @ExcludeMissing + isPublic: JsonField = JsonMissing.of(), + @JsonProperty("max_concurrency") + @ExcludeMissing + maxConcurrency: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("parent") @ExcludeMissing parent: JsonField = JsonMissing.of(), + @JsonProperty("repo_info") + @ExcludeMissing + repoInfo: JsonField = JsonMissing.of(), + @JsonProperty("stream") @ExcludeMissing stream: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + @JsonProperty("trial_count") + @ExcludeMissing + trialCount: JsonField = JsonMissing.of(), + ) : this( + data, + projectId, + scores, + task, + baseExperimentId, + baseExperimentName, + experimentName, + gitMetadataSettings, + isPublic, + maxConcurrency, + metadata, + parent, + repoInfo, + stream, + timeout, + trialCount, + mutableMapOf(), + ) - fun build(): DatasetId = DatasetId(datasetId, additionalProperties.toUnmodifiable()) - } - } + /** + * The dataset to use + * + * @throws BraintrustInvalidDataException 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") - /** Project and dataset name */ - @JsonDeserialize(builder = ProjectDatasetName.Builder::class) - @NoAutoDetect - class ProjectDatasetName - private constructor( - private val projectName: JsonField, - private val datasetName: JsonField, - private val additionalProperties: Map, - ) { + /** + * Unique identifier for the project to run the eval in + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - private var validated: Boolean = false + /** + * The functions to score the eval on + * + * @throws BraintrustInvalidDataException 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 scores(): List = scores.getRequired("scores") - private var hashCode: Int = 0 + /** + * The function to evaluate + * + * @throws BraintrustInvalidDataException 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 task(): Task = task.getRequired("task") - fun projectName(): String = projectName.getRequired("project_name") + /** + * An optional experiment id to use as a base. If specified, the new experiment will be + * summarized and compared to this experiment. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun baseExperimentId(): String? = baseExperimentId.getNullable("base_experiment_id") - fun datasetName(): String = datasetName.getRequired("dataset_name") + /** + * An optional experiment name to use as a base. If specified, the new experiment will be + * summarized and compared to this experiment. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun baseExperimentName(): String? = baseExperimentName.getNullable("base_experiment_name") - @JsonProperty("project_name") @ExcludeMissing fun _projectName() = projectName + /** + * An optional name for the experiment created by this eval. If it conflicts with an + * existing experiment, it will be suffixed with a unique identifier. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun experimentName(): String? = experimentName.getNullable("experiment_name") - @JsonProperty("dataset_name") @ExcludeMissing fun _datasetName() = datasetName + /** + * Optional settings for collecting git metadata. By default, will collect all git metadata + * fields allowed in org-level settings. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun gitMetadataSettings(): GitMetadataSettings? = + gitMetadataSettings.getNullable("git_metadata_settings") - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Whether the experiment should be public. Defaults to false. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun isPublic(): Boolean? = isPublic.getNullable("is_public") - fun validate(): ProjectDatasetName = apply { - if (!validated) { - projectName() - datasetName() - validated = true - } - } + /** + * The maximum number of tasks/scorers that will be run concurrently. Defaults to undefined, + * in which case there is no max concurrency. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxConcurrency(): Double? = maxConcurrency.getNullable("max_concurrency") - fun toBuilder() = Builder().from(this) + /** + * Optional experiment-level metadata to store about the evaluation. You can later use this + * to slice & dice across experiments. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Options for tracing the evaluation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun parent(): Parent? = parent.getNullable("parent") + + /** + * Metadata about the state of the repo when the experiment was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun repoInfo(): RepoInfo? = repoInfo.getNullable("repo_info") + + /** + * Whether to stream the results of the eval. If true, the request will return two events: + * one to indicate the experiment has started, and another upon completion. If false, the + * request will return the evaluation's summary upon completion. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun stream(): Boolean? = stream.getNullable("stream") + + /** + * The maximum duration, in milliseconds, to run the evaluation. Defaults to undefined, in + * which case there is no timeout. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Double? = timeout.getNullable("timeout") + + /** + * The number of times to run the evaluator per input. This is useful for evaluating + * applications that have non-deterministic behavior and gives you both a stronger aggregate + * measure and a sense of the variance in the results. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun trialCount(): Double? = trialCount.getNullable("trial_count") + + /** + * 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 [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 [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField> = scores + + /** + * Returns the raw JSON value of [task]. + * + * Unlike [task], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("task") @ExcludeMissing fun _task(): JsonField = task + + /** + * Returns the raw JSON value of [baseExperimentId]. + * + * Unlike [baseExperimentId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("base_experiment_id") + @ExcludeMissing + fun _baseExperimentId(): JsonField = baseExperimentId + + /** + * Returns the raw JSON value of [baseExperimentName]. + * + * Unlike [baseExperimentName], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("base_experiment_name") + @ExcludeMissing + fun _baseExperimentName(): JsonField = baseExperimentName + + /** + * Returns the raw JSON value of [experimentName]. + * + * Unlike [experimentName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("experiment_name") + @ExcludeMissing + fun _experimentName(): JsonField = experimentName + + /** + * Returns the raw JSON value of [gitMetadataSettings]. + * + * Unlike [gitMetadataSettings], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("git_metadata_settings") + @ExcludeMissing + fun _gitMetadataSettings(): JsonField = gitMetadataSettings + + /** + * Returns the raw JSON value of [isPublic]. + * + * Unlike [isPublic], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("is_public") @ExcludeMissing fun _isPublic(): JsonField = isPublic + + /** + * Returns the raw JSON value of [maxConcurrency]. + * + * Unlike [maxConcurrency], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("max_concurrency") + @ExcludeMissing + fun _maxConcurrency(): JsonField = maxConcurrency + + /** + * 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 [parent]. + * + * Unlike [parent], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("parent") @ExcludeMissing fun _parent(): JsonField = parent + + /** + * Returns the raw JSON value of [repoInfo]. + * + * Unlike [repoInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("repo_info") @ExcludeMissing fun _repoInfo(): JsonField = repoInfo + + /** + * Returns the raw JSON value of [stream]. + * + * Unlike [stream], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("stream") @ExcludeMissing fun _stream(): JsonField = stream + + /** + * 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 [trialCount]. + * + * Unlike [trialCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("trial_count") + @ExcludeMissing + fun _trialCount(): JsonField = trialCount + + @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: + * ```kotlin + * .data() + * .projectId() + * .scores() + * .task() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var data: JsonField? = null + private var projectId: JsonField? = null + private var scores: JsonField>? = null + private var task: JsonField? = null + private var baseExperimentId: JsonField = JsonMissing.of() + private var baseExperimentName: JsonField = JsonMissing.of() + private var experimentName: JsonField = JsonMissing.of() + private var gitMetadataSettings: JsonField = JsonMissing.of() + private var isPublic: JsonField = JsonMissing.of() + private var maxConcurrency: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var parent: JsonField = JsonMissing.of() + private var repoInfo: JsonField = JsonMissing.of() + private var stream: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var trialCount: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + data = body.data + projectId = body.projectId + scores = body.scores.map { it.toMutableList() } + task = body.task + baseExperimentId = body.baseExperimentId + baseExperimentName = body.baseExperimentName + experimentName = body.experimentName + gitMetadataSettings = body.gitMetadataSettings + isPublic = body.isPublic + maxConcurrency = body.maxConcurrency + metadata = body.metadata + parent = body.parent + repoInfo = body.repoInfo + stream = body.stream + timeout = body.timeout + trialCount = body.trialCount + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** The dataset to use */ + 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.ofDatasetId(datasetId)`. */ + fun data(datasetId: Data.DatasetId) = data(Data.ofDatasetId(datasetId)) + + /** Alias for calling [data] with `Data.ofProjectDatasetName(projectDatasetName)`. */ + fun data(projectDatasetName: Data.ProjectDatasetName) = + data(Data.ofProjectDatasetName(projectDatasetName)) + + /** Alias for calling [data] with `Data.ofDatasetRows(datasetRows)`. */ + fun data(datasetRows: Data.DatasetRows) = data(Data.ofDatasetRows(datasetRows)) + + /** Unique identifier for the project to run the eval in */ + 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 } + + /** The functions to score the eval on */ + fun scores(scores: List) = scores(JsonField.of(scores)) + + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun scores(scores: JsonField>) = apply { + this.scores = scores.map { it.toMutableList() } + } + + /** + * Adds a single [Score] to [scores]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addScore(score: Score) = apply { + scores = + (scores ?: JsonField.of(mutableListOf())).also { + checkKnown("scores", it).add(score) + } + } + + /** Alias for calling [addScore] with `Score.ofFunctionId(functionId)`. */ + fun addScore(functionId: Score.FunctionId) = addScore(Score.ofFunctionId(functionId)) + + /** Alias for calling [addScore] with `Score.ofProjectSlug(projectSlug)`. */ + fun addScore(projectSlug: Score.ProjectSlug) = + addScore(Score.ofProjectSlug(projectSlug)) + + /** Alias for calling [addScore] with `Score.ofGlobalFunction(globalFunction)`. */ + fun addScore(globalFunction: Score.GlobalFunction) = + addScore(Score.ofGlobalFunction(globalFunction)) + + /** Alias for calling [addScore] with `Score.ofPromptSessionId(promptSessionId)`. */ + fun addScore(promptSessionId: Score.PromptSessionId) = + addScore(Score.ofPromptSessionId(promptSessionId)) + + /** Alias for calling [addScore] with `Score.ofInlineCode(inlineCode)`. */ + fun addScore(inlineCode: Score.InlineCode) = addScore(Score.ofInlineCode(inlineCode)) + + /** Alias for calling [addScore] with `Score.ofInlinePrompt(inlinePrompt)`. */ + fun addScore(inlinePrompt: Score.InlinePrompt) = + addScore(Score.ofInlinePrompt(inlinePrompt)) + + /** The function to evaluate */ + fun task(task: Task) = task(JsonField.of(task)) + + /** + * Sets [Builder.task] to an arbitrary JSON value. + * + * You should usually call [Builder.task] with a well-typed [Task] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun task(task: JsonField) = apply { this.task = task } + + /** Alias for calling [task] with `Task.ofFunctionId(functionId)`. */ + fun task(functionId: Task.FunctionId) = task(Task.ofFunctionId(functionId)) + + /** Alias for calling [task] with `Task.ofProjectSlug(projectSlug)`. */ + fun task(projectSlug: Task.ProjectSlug) = task(Task.ofProjectSlug(projectSlug)) + + /** Alias for calling [task] with `Task.ofGlobalFunction(globalFunction)`. */ + fun task(globalFunction: Task.GlobalFunction) = + task(Task.ofGlobalFunction(globalFunction)) + + /** Alias for calling [task] with `Task.ofPromptSessionId(promptSessionId)`. */ + fun task(promptSessionId: Task.PromptSessionId) = + task(Task.ofPromptSessionId(promptSessionId)) + + /** Alias for calling [task] with `Task.ofInlineCode(inlineCode)`. */ + fun task(inlineCode: Task.InlineCode) = task(Task.ofInlineCode(inlineCode)) + + /** Alias for calling [task] with `Task.ofInlinePrompt(inlinePrompt)`. */ + fun task(inlinePrompt: Task.InlinePrompt) = task(Task.ofInlinePrompt(inlinePrompt)) + + /** + * An optional experiment id to use as a base. If specified, the new experiment will be + * summarized and compared to this experiment. + */ + fun baseExperimentId(baseExperimentId: String?) = + baseExperimentId(JsonField.ofNullable(baseExperimentId)) + + /** + * Sets [Builder.baseExperimentId] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExperimentId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun baseExperimentId(baseExperimentId: JsonField) = apply { + this.baseExperimentId = baseExperimentId + } + + /** + * An optional experiment name to use as a base. If specified, the new experiment will + * be summarized and compared to this experiment. + */ + fun baseExperimentName(baseExperimentName: String?) = + baseExperimentName(JsonField.ofNullable(baseExperimentName)) + + /** + * Sets [Builder.baseExperimentName] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExperimentName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun baseExperimentName(baseExperimentName: JsonField) = apply { + this.baseExperimentName = baseExperimentName + } + + /** + * An optional name for the experiment created by this eval. If it conflicts with an + * existing experiment, it will be suffixed with a unique identifier. + */ + fun experimentName(experimentName: String) = + experimentName(JsonField.of(experimentName)) + + /** + * Sets [Builder.experimentName] to an arbitrary JSON value. + * + * You should usually call [Builder.experimentName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun experimentName(experimentName: JsonField) = apply { + this.experimentName = experimentName + } + + /** + * Optional settings for collecting git metadata. By default, will collect all git + * metadata fields allowed in org-level settings. + */ + fun gitMetadataSettings(gitMetadataSettings: GitMetadataSettings?) = + gitMetadataSettings(JsonField.ofNullable(gitMetadataSettings)) + + /** + * Sets [Builder.gitMetadataSettings] to an arbitrary JSON value. + * + * You should usually call [Builder.gitMetadataSettings] with a well-typed + * [GitMetadataSettings] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun gitMetadataSettings(gitMetadataSettings: JsonField) = apply { + this.gitMetadataSettings = gitMetadataSettings + } + + /** Whether the experiment should be public. Defaults to false. */ + fun isPublic(isPublic: Boolean?) = isPublic(JsonField.ofNullable(isPublic)) + + /** + * Alias for [Builder.isPublic]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun isPublic(isPublic: Boolean) = isPublic(isPublic as Boolean?) + + /** + * Sets [Builder.isPublic] to an arbitrary JSON value. + * + * You should usually call [Builder.isPublic] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isPublic(isPublic: JsonField) = apply { this.isPublic = isPublic } + + /** + * The maximum number of tasks/scorers that will be run concurrently. Defaults to + * undefined, in which case there is no max concurrency. + */ + fun maxConcurrency(maxConcurrency: Double?) = + maxConcurrency(JsonField.ofNullable(maxConcurrency)) + + /** + * Alias for [Builder.maxConcurrency]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun maxConcurrency(maxConcurrency: Double) = maxConcurrency(maxConcurrency as Double?) + + /** + * Sets [Builder.maxConcurrency] to an arbitrary JSON value. + * + * You should usually call [Builder.maxConcurrency] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxConcurrency(maxConcurrency: JsonField) = apply { + this.maxConcurrency = maxConcurrency + } + + /** + * Optional experiment-level metadata to store about the evaluation. You can later use + * this to slice & dice across experiments. + */ + 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 } + + /** Options for tracing the evaluation */ + fun parent(parent: Parent) = parent(JsonField.of(parent)) + + /** + * Sets [Builder.parent] to an arbitrary JSON value. + * + * You should usually call [Builder.parent] with a well-typed [Parent] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun parent(parent: JsonField) = apply { this.parent = parent } + + /** Alias for calling [parent] with `Parent.ofSpanParentStruct(spanParentStruct)`. */ + fun parent(spanParentStruct: Parent.SpanParentStruct) = + parent(Parent.ofSpanParentStruct(spanParentStruct)) + + /** Alias for calling [parent] with `Parent.ofString(string)`. */ + fun parent(string: String) = parent(Parent.ofString(string)) + + /** Metadata about the state of the repo when the experiment was created */ + fun repoInfo(repoInfo: RepoInfo?) = repoInfo(JsonField.ofNullable(repoInfo)) + + /** + * Sets [Builder.repoInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.repoInfo] with a well-typed [RepoInfo] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun repoInfo(repoInfo: JsonField) = apply { this.repoInfo = repoInfo } + + /** + * Whether to stream the results of the eval. If true, the request will return two + * events: one to indicate the experiment has started, and another upon completion. If + * false, the request will return the evaluation's summary upon completion. + */ + fun stream(stream: Boolean) = stream(JsonField.of(stream)) + + /** + * Sets [Builder.stream] to an arbitrary JSON value. + * + * You should usually call [Builder.stream] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun stream(stream: JsonField) = apply { this.stream = stream } + + /** + * The maximum duration, in milliseconds, to run the evaluation. Defaults to undefined, + * in which case there is no timeout. + */ + fun timeout(timeout: Double?) = timeout(JsonField.ofNullable(timeout)) + + /** + * Alias for [Builder.timeout]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun timeout(timeout: Double) = timeout(timeout as Double?) + + /** + * 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 } + + /** + * The number of times to run the evaluator per input. This is useful for evaluating + * applications that have non-deterministic behavior and gives you both a stronger + * aggregate measure and a sense of the variance in the results. + */ + fun trialCount(trialCount: Double?) = trialCount(JsonField.ofNullable(trialCount)) + + /** + * Alias for [Builder.trialCount]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun trialCount(trialCount: Double) = trialCount(trialCount as Double?) + + /** + * Sets [Builder.trialCount] to an arbitrary JSON value. + * + * You should usually call [Builder.trialCount] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun trialCount(trialCount: JsonField) = apply { this.trialCount = trialCount } + + 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: + * ```kotlin + * .data() + * .projectId() + * .scores() + * .task() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("data", data), + checkRequired("projectId", projectId), + checkRequired("scores", scores).map { it.toImmutable() }, + checkRequired("task", task), + baseExperimentId, + baseExperimentName, + experimentName, + gitMetadataSettings, + isPublic, + maxConcurrency, + metadata, + parent, + repoInfo, + stream, + timeout, + trialCount, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + data().validate() + projectId() + scores().forEach { it.validate() } + task().validate() + baseExperimentId() + baseExperimentName() + experimentName() + gitMetadataSettings()?.validate() + isPublic() + maxConcurrency() + metadata()?.validate() + parent()?.validate() + repoInfo()?.validate() + stream() + timeout() + trialCount() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (data.asKnown()?.validity() ?: 0) + + (if (projectId.asKnown() == null) 0 else 1) + + (scores.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (task.asKnown()?.validity() ?: 0) + + (if (baseExperimentId.asKnown() == null) 0 else 1) + + (if (baseExperimentName.asKnown() == null) 0 else 1) + + (if (experimentName.asKnown() == null) 0 else 1) + + (gitMetadataSettings.asKnown()?.validity() ?: 0) + + (if (isPublic.asKnown() == null) 0 else 1) + + (if (maxConcurrency.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (parent.asKnown()?.validity() ?: 0) + + (repoInfo.asKnown()?.validity() ?: 0) + + (if (stream.asKnown() == null) 0 else 1) + + (if (timeout.asKnown() == null) 0 else 1) + + (if (trialCount.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + data == other.data && + projectId == other.projectId && + scores == other.scores && + task == other.task && + baseExperimentId == other.baseExperimentId && + baseExperimentName == other.baseExperimentName && + experimentName == other.experimentName && + gitMetadataSettings == other.gitMetadataSettings && + isPublic == other.isPublic && + maxConcurrency == other.maxConcurrency && + metadata == other.metadata && + parent == other.parent && + repoInfo == other.repoInfo && + stream == other.stream && + timeout == other.timeout && + trialCount == other.trialCount && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + data, + projectId, + scores, + task, + baseExperimentId, + baseExperimentName, + experimentName, + gitMetadataSettings, + isPublic, + maxConcurrency, + metadata, + parent, + repoInfo, + stream, + timeout, + trialCount, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{data=$data, projectId=$projectId, scores=$scores, task=$task, baseExperimentId=$baseExperimentId, baseExperimentName=$baseExperimentName, experimentName=$experimentName, gitMetadataSettings=$gitMetadataSettings, isPublic=$isPublic, maxConcurrency=$maxConcurrency, metadata=$metadata, parent=$parent, repoInfo=$repoInfo, stream=$stream, timeout=$timeout, trialCount=$trialCount, additionalProperties=$additionalProperties}" + } + + /** The dataset to use */ + @JsonDeserialize(using = Data.Deserializer::class) + @JsonSerialize(using = Data.Serializer::class) + class Data + private constructor( + private val datasetId: DatasetId? = null, + private val projectDatasetName: ProjectDatasetName? = null, + private val datasetRows: DatasetRows? = null, + private val _json: JsonValue? = null, + ) { + + /** Dataset id */ + fun datasetId(): DatasetId? = datasetId + + /** Project and dataset name */ + fun projectDatasetName(): ProjectDatasetName? = projectDatasetName + + /** Dataset rows */ + fun datasetRows(): DatasetRows? = datasetRows + + fun isDatasetId(): Boolean = datasetId != null + + fun isProjectDatasetName(): Boolean = projectDatasetName != null + + fun isDatasetRows(): Boolean = datasetRows != null + + /** Dataset id */ + fun asDatasetId(): DatasetId = datasetId.getOrThrow("datasetId") + + /** Project and dataset name */ + fun asProjectDatasetName(): ProjectDatasetName = + projectDatasetName.getOrThrow("projectDatasetName") + + /** Dataset rows */ + fun asDatasetRows(): DatasetRows = datasetRows.getOrThrow("datasetRows") + + fun _json(): JsonValue? = _json + + fun accept(visitor: Visitor): T = + when { + datasetId != null -> visitor.visitDatasetId(datasetId) + projectDatasetName != null -> visitor.visitProjectDatasetName(projectDatasetName) + datasetRows != null -> visitor.visitDatasetRows(datasetRows) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitDatasetId(datasetId: DatasetId) { + datasetId.validate() + } + + override fun visitProjectDatasetName(projectDatasetName: ProjectDatasetName) { + projectDatasetName.validate() + } + + override fun visitDatasetRows(datasetRows: DatasetRows) { + datasetRows.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitDatasetId(datasetId: DatasetId) = datasetId.validity() + + override fun visitProjectDatasetName(projectDatasetName: ProjectDatasetName) = + projectDatasetName.validity() + + override fun visitDatasetRows(datasetRows: DatasetRows) = datasetRows.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + datasetId == other.datasetId && + projectDatasetName == other.projectDatasetName && + datasetRows == other.datasetRows + } + + override fun hashCode(): Int = Objects.hash(datasetId, projectDatasetName, datasetRows) + + override fun toString(): String = + when { + datasetId != null -> "Data{datasetId=$datasetId}" + projectDatasetName != null -> "Data{projectDatasetName=$projectDatasetName}" + datasetRows != null -> "Data{datasetRows=$datasetRows}" + _json != null -> "Data{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Data") + } + + companion object { + + /** Dataset id */ + fun ofDatasetId(datasetId: DatasetId) = Data(datasetId = datasetId) + + /** Project and dataset name */ + fun ofProjectDatasetName(projectDatasetName: ProjectDatasetName) = + Data(projectDatasetName = projectDatasetName) + + /** Dataset rows */ + fun ofDatasetRows(datasetRows: DatasetRows) = Data(datasetRows = datasetRows) + } + + /** An interface that defines how to map each variant of [Data] to a value of type [T]. */ + interface Visitor { + + /** Dataset id */ + fun visitDatasetId(datasetId: DatasetId): T + + /** Project and dataset name */ + fun visitProjectDatasetName(projectDatasetName: ProjectDatasetName): T + + /** Dataset rows */ + fun visitDatasetRows(datasetRows: DatasetRows): 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 BraintrustInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("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(datasetId = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Data(projectDatasetName = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Data(datasetRows = 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.datasetId != null -> generator.writeObject(value.datasetId) + value.projectDatasetName != null -> + generator.writeObject(value.projectDatasetName) + value.datasetRows != null -> generator.writeObject(value.datasetRows) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Data") + } + } + } + + /** Dataset id */ + class DatasetId + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val datasetId: JsonField, + private val _internalBtql: JsonField<_InternalBtql>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("dataset_id") + @ExcludeMissing + datasetId: JsonField = JsonMissing.of(), + @JsonProperty("_internal_btql") + @ExcludeMissing + _internalBtql: JsonField<_InternalBtql> = JsonMissing.of(), + ) : this(datasetId, _internalBtql, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 datasetId(): String = datasetId.getRequired("dataset_id") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun _internalBtql(): _InternalBtql? = _internalBtql.getNullable("_internal_btql") + + /** + * Returns the raw JSON value of [datasetId]. + * + * Unlike [datasetId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("dataset_id") + @ExcludeMissing + fun _datasetId(): JsonField = datasetId + + /** + * Returns the raw JSON value of [_internalBtql]. + * + * Unlike [_internalBtql], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("_internal_btql") + @ExcludeMissing + fun __internalBtql(): JsonField<_InternalBtql> = _internalBtql + + @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 [DatasetId]. + * + * The following fields are required: + * ```kotlin + * .datasetId() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [DatasetId]. */ + class Builder internal constructor() { + + private var datasetId: JsonField? = null + private var _internalBtql: JsonField<_InternalBtql> = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(datasetId: DatasetId) = apply { + this.datasetId = datasetId.datasetId + _internalBtql = datasetId._internalBtql + additionalProperties = datasetId.additionalProperties.toMutableMap() + } + + fun datasetId(datasetId: String) = datasetId(JsonField.of(datasetId)) + + /** + * Sets [Builder.datasetId] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun datasetId(datasetId: JsonField) = apply { this.datasetId = datasetId } + + fun _internalBtql(_internalBtql: _InternalBtql?) = + _internalBtql(JsonField.ofNullable(_internalBtql)) + + /** + * Sets [Builder._internalBtql] to an arbitrary JSON value. + * + * You should usually call [Builder._internalBtql] with a well-typed [_InternalBtql] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun _internalBtql(_internalBtql: JsonField<_InternalBtql>) = apply { + this._internalBtql = _internalBtql + } + + 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 [DatasetId]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .datasetId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DatasetId = + DatasetId( + checkRequired("datasetId", datasetId), + _internalBtql, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): DatasetId = apply { + if (validated) { + return@apply + } + + datasetId() + _internalBtql()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (datasetId.asKnown() == null) 0 else 1) + + (_internalBtql.asKnown()?.validity() ?: 0) + + class _InternalBtql + @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 [_InternalBtql]. + */ + fun builder() = Builder() + } + + /** A builder for [_InternalBtql]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(_internalBtql: _InternalBtql) = apply { + additionalProperties = _internalBtql.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 [_InternalBtql]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): _InternalBtql = _InternalBtql(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): _InternalBtql = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 _InternalBtql && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "_InternalBtql{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetId && + datasetId == other.datasetId && + _internalBtql == other._internalBtql && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(datasetId, _internalBtql, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DatasetId{datasetId=$datasetId, _internalBtql=$_internalBtql, additionalProperties=$additionalProperties}" + } + + /** Project and dataset name */ + class ProjectDatasetName + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val datasetName: JsonField, + private val projectName: JsonField, + private val _internalBtql: JsonField<_InternalBtql>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("dataset_name") + @ExcludeMissing + datasetName: JsonField = JsonMissing.of(), + @JsonProperty("project_name") + @ExcludeMissing + projectName: JsonField = JsonMissing.of(), + @JsonProperty("_internal_btql") + @ExcludeMissing + _internalBtql: JsonField<_InternalBtql> = JsonMissing.of(), + ) : this(datasetName, projectName, _internalBtql, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 datasetName(): String = datasetName.getRequired("dataset_name") + + /** + * @throws BraintrustInvalidDataException 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 projectName(): String = projectName.getRequired("project_name") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun _internalBtql(): _InternalBtql? = _internalBtql.getNullable("_internal_btql") + + /** + * Returns the raw JSON value of [datasetName]. + * + * Unlike [datasetName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("dataset_name") + @ExcludeMissing + fun _datasetName(): JsonField = datasetName + + /** + * Returns the raw JSON value of [projectName]. + * + * Unlike [projectName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("project_name") + @ExcludeMissing + fun _projectName(): JsonField = projectName + + /** + * Returns the raw JSON value of [_internalBtql]. + * + * Unlike [_internalBtql], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("_internal_btql") + @ExcludeMissing + fun __internalBtql(): JsonField<_InternalBtql> = _internalBtql + + @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 [ProjectDatasetName]. + * + * The following fields are required: + * ```kotlin + * .datasetName() + * .projectName() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ProjectDatasetName]. */ + class Builder internal constructor() { + + private var datasetName: JsonField? = null + private var projectName: JsonField? = null + private var _internalBtql: JsonField<_InternalBtql> = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(projectDatasetName: ProjectDatasetName) = apply { + datasetName = projectDatasetName.datasetName + projectName = projectDatasetName.projectName + _internalBtql = projectDatasetName._internalBtql + additionalProperties = projectDatasetName.additionalProperties.toMutableMap() + } + + fun datasetName(datasetName: String) = datasetName(JsonField.of(datasetName)) + + /** + * Sets [Builder.datasetName] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun datasetName(datasetName: JsonField) = apply { + this.datasetName = datasetName + } + + fun projectName(projectName: String) = projectName(JsonField.of(projectName)) + + /** + * Sets [Builder.projectName] to an arbitrary JSON value. + * + * You should usually call [Builder.projectName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun projectName(projectName: JsonField) = apply { + this.projectName = projectName + } + + fun _internalBtql(_internalBtql: _InternalBtql?) = + _internalBtql(JsonField.ofNullable(_internalBtql)) + + /** + * Sets [Builder._internalBtql] to an arbitrary JSON value. + * + * You should usually call [Builder._internalBtql] with a well-typed [_InternalBtql] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun _internalBtql(_internalBtql: JsonField<_InternalBtql>) = apply { + this._internalBtql = _internalBtql + } + + 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 [ProjectDatasetName]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .datasetName() + * .projectName() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectDatasetName = + ProjectDatasetName( + checkRequired("datasetName", datasetName), + checkRequired("projectName", projectName), + _internalBtql, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ProjectDatasetName = apply { + if (validated) { + return@apply + } + + datasetName() + projectName() + _internalBtql()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (datasetName.asKnown() == null) 0 else 1) + + (if (projectName.asKnown() == null) 0 else 1) + + (_internalBtql.asKnown()?.validity() ?: 0) + + class _InternalBtql + @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 [_InternalBtql]. + */ + fun builder() = Builder() + } + + /** A builder for [_InternalBtql]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(_internalBtql: _InternalBtql) = apply { + additionalProperties = _internalBtql.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 [_InternalBtql]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): _InternalBtql = _InternalBtql(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): _InternalBtql = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 _InternalBtql && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "_InternalBtql{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } return other is ProjectDatasetName && - this.projectName == other.projectName && - this.datasetName == other.datasetName && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - projectName, - datasetName, - additionalProperties, + datasetName == other.datasetName && + projectName == other.projectName && + _internalBtql == other._internalBtql && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(datasetName, projectName, _internalBtql, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectDatasetName{datasetName=$datasetName, projectName=$projectName, _internalBtql=$_internalBtql, additionalProperties=$additionalProperties}" + } + + /** Dataset rows */ + class DatasetRows + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val data: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("data") + @ExcludeMissing + data: JsonField> = JsonMissing.of() + ) : this(data, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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(): List = data.getRequired("data") + + /** + * 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 + + @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 [DatasetRows]. + * + * The following fields are required: + * ```kotlin + * .data() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [DatasetRows]. */ + class Builder internal constructor() { + + private var data: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(datasetRows: DatasetRows) = apply { + data = datasetRows.data.map { it.toMutableList() } + additionalProperties = datasetRows.additionalProperties.toMutableMap() + } + + fun data(data: List) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed `List` 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.map { it.toMutableList() } + } + + /** + * Adds a single [JsonValue] to [Builder.data]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addData(data: JsonValue) = apply { + this.data = + (this.data ?: JsonField.of(mutableListOf())).also { + checkKnown("data", it).add(data) + } + } + + 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 [DatasetRows]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .data() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): DatasetRows = + DatasetRows( + checkRequired("data", data).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): DatasetRows = apply { + if (validated) { + return@apply + } + + data() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (data.asKnown()?.sumOf { (if (it == null) 0 else 1).toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is DatasetRows && + data == other.data && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(data, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DatasetRows{data=$data, additionalProperties=$additionalProperties}" + } + } + + /** The function to evaluate */ + @JsonDeserialize(using = Score.Deserializer::class) + @JsonSerialize(using = Score.Serializer::class) + class Score + private constructor( + private val functionId: FunctionId? = null, + private val projectSlug: ProjectSlug? = null, + private val globalFunction: GlobalFunction? = null, + private val promptSessionId: PromptSessionId? = null, + private val inlineCode: InlineCode? = null, + private val inlinePrompt: InlinePrompt? = null, + private val _json: JsonValue? = null, + ) { + + /** Function id */ + fun functionId(): FunctionId? = functionId + + /** Project name and slug */ + fun projectSlug(): ProjectSlug? = projectSlug + + /** Global function name */ + fun globalFunction(): GlobalFunction? = globalFunction + + /** Prompt session id */ + fun promptSessionId(): PromptSessionId? = promptSessionId + + /** Inline code function */ + fun inlineCode(): InlineCode? = inlineCode + + /** Inline prompt definition */ + fun inlinePrompt(): InlinePrompt? = inlinePrompt + + fun isFunctionId(): Boolean = functionId != null + + fun isProjectSlug(): Boolean = projectSlug != null + + fun isGlobalFunction(): Boolean = globalFunction != null + + fun isPromptSessionId(): Boolean = promptSessionId != null + + fun isInlineCode(): Boolean = inlineCode != null + + fun isInlinePrompt(): Boolean = inlinePrompt != null + + /** Function id */ + fun asFunctionId(): FunctionId = functionId.getOrThrow("functionId") + + /** Project name and slug */ + fun asProjectSlug(): ProjectSlug = projectSlug.getOrThrow("projectSlug") + + /** Global function name */ + fun asGlobalFunction(): GlobalFunction = globalFunction.getOrThrow("globalFunction") + + /** Prompt session id */ + fun asPromptSessionId(): PromptSessionId = promptSessionId.getOrThrow("promptSessionId") + + /** Inline code function */ + fun asInlineCode(): InlineCode = inlineCode.getOrThrow("inlineCode") + + /** Inline prompt definition */ + fun asInlinePrompt(): InlinePrompt = inlinePrompt.getOrThrow("inlinePrompt") + + fun _json(): JsonValue? = _json + + fun accept(visitor: Visitor): T = + when { + functionId != null -> visitor.visitFunctionId(functionId) + projectSlug != null -> visitor.visitProjectSlug(projectSlug) + globalFunction != null -> visitor.visitGlobalFunction(globalFunction) + promptSessionId != null -> visitor.visitPromptSessionId(promptSessionId) + inlineCode != null -> visitor.visitInlineCode(inlineCode) + inlinePrompt != null -> visitor.visitInlinePrompt(inlinePrompt) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Score = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitFunctionId(functionId: FunctionId) { + functionId.validate() + } + + override fun visitProjectSlug(projectSlug: ProjectSlug) { + projectSlug.validate() + } + + override fun visitGlobalFunction(globalFunction: GlobalFunction) { + globalFunction.validate() + } + + override fun visitPromptSessionId(promptSessionId: PromptSessionId) { + promptSessionId.validate() + } + + override fun visitInlineCode(inlineCode: InlineCode) { + inlineCode.validate() + } + + override fun visitInlinePrompt(inlinePrompt: InlinePrompt) { + inlinePrompt.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitFunctionId(functionId: FunctionId) = functionId.validity() + + override fun visitProjectSlug(projectSlug: ProjectSlug) = projectSlug.validity() + + override fun visitGlobalFunction(globalFunction: GlobalFunction) = + globalFunction.validity() + + override fun visitPromptSessionId(promptSessionId: PromptSessionId) = + promptSessionId.validity() + + override fun visitInlineCode(inlineCode: InlineCode) = inlineCode.validity() + + override fun visitInlinePrompt(inlinePrompt: InlinePrompt) = + inlinePrompt.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Score && + functionId == other.functionId && + projectSlug == other.projectSlug && + globalFunction == other.globalFunction && + promptSessionId == other.promptSessionId && + inlineCode == other.inlineCode && + inlinePrompt == other.inlinePrompt + } + + override fun hashCode(): Int = + Objects.hash( + functionId, + projectSlug, + globalFunction, + promptSessionId, + inlineCode, + inlinePrompt, + ) + + override fun toString(): String = + when { + functionId != null -> "Score{functionId=$functionId}" + projectSlug != null -> "Score{projectSlug=$projectSlug}" + globalFunction != null -> "Score{globalFunction=$globalFunction}" + promptSessionId != null -> "Score{promptSessionId=$promptSessionId}" + inlineCode != null -> "Score{inlineCode=$inlineCode}" + inlinePrompt != null -> "Score{inlinePrompt=$inlinePrompt}" + _json != null -> "Score{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Score") + } + + companion object { + + /** Function id */ + fun ofFunctionId(functionId: FunctionId) = Score(functionId = functionId) + + /** Project name and slug */ + fun ofProjectSlug(projectSlug: ProjectSlug) = Score(projectSlug = projectSlug) + + /** Global function name */ + fun ofGlobalFunction(globalFunction: GlobalFunction) = + Score(globalFunction = globalFunction) + + /** Prompt session id */ + fun ofPromptSessionId(promptSessionId: PromptSessionId) = + Score(promptSessionId = promptSessionId) + + /** Inline code function */ + fun ofInlineCode(inlineCode: InlineCode) = Score(inlineCode = inlineCode) + + /** Inline prompt definition */ + fun ofInlinePrompt(inlinePrompt: InlinePrompt) = Score(inlinePrompt = inlinePrompt) + } + + /** An interface that defines how to map each variant of [Score] to a value of type [T]. */ + interface Visitor { + + /** Function id */ + fun visitFunctionId(functionId: FunctionId): T + + /** Project name and slug */ + fun visitProjectSlug(projectSlug: ProjectSlug): T + + /** Global function name */ + fun visitGlobalFunction(globalFunction: GlobalFunction): T + + /** Prompt session id */ + fun visitPromptSessionId(promptSessionId: PromptSessionId): T + + /** Inline code function */ + fun visitInlineCode(inlineCode: InlineCode): T + + /** Inline prompt definition */ + fun visitInlinePrompt(inlinePrompt: InlinePrompt): T + + /** + * Maps an unknown variant of [Score] to a value of type [T]. + * + * An instance of [Score] 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 BraintrustInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("Unknown Score: $json") + } + } + + internal class Deserializer : BaseDeserializer(Score::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Score { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Score(functionId = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Score(projectSlug = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Score(globalFunction = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Score(promptSessionId = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Score(inlineCode = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Score(inlinePrompt = 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 -> Score(_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(Score::class) { + + override fun serialize( + value: Score, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.functionId != null -> generator.writeObject(value.functionId) + value.projectSlug != null -> generator.writeObject(value.projectSlug) + value.globalFunction != null -> generator.writeObject(value.globalFunction) + value.promptSessionId != null -> generator.writeObject(value.promptSessionId) + value.inlineCode != null -> generator.writeObject(value.inlineCode) + value.inlinePrompt != null -> generator.writeObject(value.inlinePrompt) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Score") + } + } + } + + /** Function id */ + class FunctionId + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val functionId: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("function_id") + @ExcludeMissing + functionId: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(functionId, version, mutableMapOf()) + + /** + * The ID of the function + * + * @throws BraintrustInvalidDataException 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 functionId(): String = functionId.getRequired("function_id") + + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun version(): String? = version.getNullable("version") + + /** + * Returns the raw JSON value of [functionId]. + * + * Unlike [functionId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_id") + @ExcludeMissing + fun _functionId(): JsonField = functionId + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version + + @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 [FunctionId]. + * + * The following fields are required: + * ```kotlin + * .functionId() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [FunctionId]. */ + class Builder internal constructor() { + + private var functionId: JsonField? = null + private var version: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(functionId: FunctionId) = apply { + this.functionId = functionId.functionId + version = functionId.version + additionalProperties = functionId.additionalProperties.toMutableMap() + } + + /** The ID of the function */ + fun functionId(functionId: String) = functionId(JsonField.of(functionId)) + + /** + * Sets [Builder.functionId] to an arbitrary JSON value. + * + * You should usually call [Builder.functionId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun functionId(functionId: JsonField) = apply { + this.functionId = functionId + } + + /** The version of the function */ + fun version(version: String) = version(JsonField.of(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun version(version: JsonField) = apply { this.version = version } + + 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 [FunctionId]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .functionId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionId = + FunctionId( + checkRequired("functionId", functionId), + version, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): FunctionId = apply { + if (validated) { + return@apply + } + + functionId() + version() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (functionId.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FunctionId && + functionId == other.functionId && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(functionId, version, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FunctionId{functionId=$functionId, version=$version, additionalProperties=$additionalProperties}" + } + + /** Project name and slug */ + class ProjectSlug + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val projectName: JsonField, + private val slug: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("project_name") + @ExcludeMissing + projectName: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(projectName, slug, version, mutableMapOf()) + + /** + * The name of the project containing the function + * + * @throws BraintrustInvalidDataException 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 projectName(): String = projectName.getRequired("project_name") + + /** + * The slug of the function + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") + + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun version(): String? = version.getNullable("version") + + /** + * Returns the raw JSON value of [projectName]. + * + * Unlike [projectName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("project_name") + @ExcludeMissing + fun _projectName(): JsonField = projectName + + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version + + @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 [ProjectSlug]. + * + * The following fields are required: + * ```kotlin + * .projectName() + * .slug() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ProjectSlug]. */ + class Builder internal constructor() { + + private var projectName: JsonField? = null + private var slug: JsonField? = null + private var version: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(projectSlug: ProjectSlug) = apply { + projectName = projectSlug.projectName + slug = projectSlug.slug + version = projectSlug.version + additionalProperties = projectSlug.additionalProperties.toMutableMap() + } + + /** The name of the project containing the function */ + fun projectName(projectName: String) = projectName(JsonField.of(projectName)) + + /** + * Sets [Builder.projectName] to an arbitrary JSON value. + * + * You should usually call [Builder.projectName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun projectName(projectName: JsonField) = apply { + this.projectName = projectName + } + + /** The slug of the function */ + fun slug(slug: String) = slug(JsonField.of(slug)) + + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun slug(slug: JsonField) = apply { this.slug = slug } + + /** The version of the function */ + fun version(version: String) = version(JsonField.of(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun version(version: JsonField) = apply { this.version = version } + + 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 [ProjectSlug]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .projectName() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectSlug = + ProjectSlug( + checkRequired("projectName", projectName), + checkRequired("slug", slug), + version, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ProjectSlug = apply { + if (validated) { + return@apply + } + + projectName() + slug() + version() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (projectName.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectSlug && + projectName == other.projectName && + slug == other.slug && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(projectName, slug, version, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectSlug{projectName=$projectName, slug=$slug, version=$version, additionalProperties=$additionalProperties}" + } + + /** Global function name */ + class GlobalFunction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val globalFunction: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("global_function") + @ExcludeMissing + globalFunction: JsonField = JsonMissing.of() + ) : this(globalFunction, mutableMapOf()) + + /** + * The name of the global function. Currently, the global namespace includes the + * functions in autoevals + * + * @throws BraintrustInvalidDataException 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 globalFunction(): String = globalFunction.getRequired("global_function") + + /** + * Returns the raw JSON value of [globalFunction]. + * + * Unlike [globalFunction], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("global_function") + @ExcludeMissing + fun _globalFunction(): JsonField = globalFunction + + @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 [GlobalFunction]. + * + * The following fields are required: + * ```kotlin + * .globalFunction() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [GlobalFunction]. */ + class Builder internal constructor() { + + private var globalFunction: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(globalFunction: GlobalFunction) = apply { + this.globalFunction = globalFunction.globalFunction + additionalProperties = globalFunction.additionalProperties.toMutableMap() + } + + /** + * The name of the global function. Currently, the global namespace includes the + * functions in autoevals + */ + fun globalFunction(globalFunction: String) = + globalFunction(JsonField.of(globalFunction)) + + /** + * Sets [Builder.globalFunction] to an arbitrary JSON value. + * + * You should usually call [Builder.globalFunction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun globalFunction(globalFunction: JsonField) = apply { + this.globalFunction = globalFunction + } + + 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 [GlobalFunction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .globalFunction() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GlobalFunction = + GlobalFunction( + checkRequired("globalFunction", globalFunction), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GlobalFunction = apply { + if (validated) { + return@apply + } + + globalFunction() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (globalFunction.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GlobalFunction && + globalFunction == other.globalFunction && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(globalFunction, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GlobalFunction{globalFunction=$globalFunction, additionalProperties=$additionalProperties}" + } + + /** Prompt session id */ + class PromptSessionId + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val promptSessionFunctionId: JsonField, + private val promptSessionId: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("prompt_session_function_id") + @ExcludeMissing + promptSessionFunctionId: JsonField = JsonMissing.of(), + @JsonProperty("prompt_session_id") + @ExcludeMissing + promptSessionId: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(promptSessionFunctionId, promptSessionId, version, mutableMapOf()) + + /** + * The ID of the function in the prompt session + * + * @throws BraintrustInvalidDataException 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 promptSessionFunctionId(): String = + promptSessionFunctionId.getRequired("prompt_session_function_id") + + /** + * The ID of the prompt session + * + * @throws BraintrustInvalidDataException 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 promptSessionId(): String = promptSessionId.getRequired("prompt_session_id") + + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun version(): String? = version.getNullable("version") + + /** + * Returns the raw JSON value of [promptSessionFunctionId]. + * + * Unlike [promptSessionFunctionId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("prompt_session_function_id") + @ExcludeMissing + fun _promptSessionFunctionId(): JsonField = promptSessionFunctionId + + /** + * Returns the raw JSON value of [promptSessionId]. + * + * Unlike [promptSessionId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("prompt_session_id") + @ExcludeMissing + fun _promptSessionId(): JsonField = promptSessionId + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version + + @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 [PromptSessionId]. + * + * The following fields are required: + * ```kotlin + * .promptSessionFunctionId() + * .promptSessionId() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [PromptSessionId]. */ + class Builder internal constructor() { + + private var promptSessionFunctionId: JsonField? = null + private var promptSessionId: JsonField? = null + private var version: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(promptSessionId: PromptSessionId) = apply { + promptSessionFunctionId = promptSessionId.promptSessionFunctionId + this.promptSessionId = promptSessionId.promptSessionId + version = promptSessionId.version + additionalProperties = promptSessionId.additionalProperties.toMutableMap() + } + + /** The ID of the function in the prompt session */ + fun promptSessionFunctionId(promptSessionFunctionId: String) = + promptSessionFunctionId(JsonField.of(promptSessionFunctionId)) + + /** + * Sets [Builder.promptSessionFunctionId] to an arbitrary JSON value. + * + * You should usually call [Builder.promptSessionFunctionId] with a well-typed + * [String] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun promptSessionFunctionId(promptSessionFunctionId: JsonField) = apply { + this.promptSessionFunctionId = promptSessionFunctionId + } + + /** The ID of the prompt session */ + fun promptSessionId(promptSessionId: String) = + promptSessionId(JsonField.of(promptSessionId)) + + /** + * Sets [Builder.promptSessionId] to an arbitrary JSON value. + * + * You should usually call [Builder.promptSessionId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun promptSessionId(promptSessionId: JsonField) = apply { + this.promptSessionId = promptSessionId + } + + /** The version of the function */ + fun version(version: String) = version(JsonField.of(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun version(version: JsonField) = apply { this.version = version } + + 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 [PromptSessionId]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .promptSessionFunctionId() + * .promptSessionId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PromptSessionId = + PromptSessionId( + checkRequired("promptSessionFunctionId", promptSessionFunctionId), + checkRequired("promptSessionId", promptSessionId), + version, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): PromptSessionId = apply { + if (validated) { + return@apply + } + + promptSessionFunctionId() + promptSessionId() + version() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (promptSessionFunctionId.asKnown() == null) 0 else 1) + + (if (promptSessionId.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PromptSessionId && + promptSessionFunctionId == other.promptSessionFunctionId && + promptSessionId == other.promptSessionId && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + promptSessionFunctionId, + promptSessionId, + version, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PromptSessionId{promptSessionFunctionId=$promptSessionFunctionId, promptSessionId=$promptSessionId, version=$version, additionalProperties=$additionalProperties}" + } + + /** Inline code function */ + class InlineCode + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val code: JsonField, + private val inlineContext: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("code") @ExcludeMissing code: JsonField = JsonMissing.of(), + @JsonProperty("inline_context") + @ExcludeMissing + inlineContext: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(code, inlineContext, name, mutableMapOf()) + + /** + * The inline code to execute + * + * @throws BraintrustInvalidDataException 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 code(): String = code.getRequired("code") + + /** + * @throws BraintrustInvalidDataException 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 inlineContext(): InlineContext = inlineContext.getRequired("inline_context") + + /** + * The name of the inline code function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * Returns the raw JSON value of [code]. + * + * Unlike [code], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("code") @ExcludeMissing fun _code(): JsonField = code + + /** + * Returns the raw JSON value of [inlineContext]. + * + * Unlike [inlineContext], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("inline_context") + @ExcludeMissing + fun _inlineContext(): JsonField = inlineContext + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @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 [InlineCode]. + * + * The following fields are required: + * ```kotlin + * .code() + * .inlineContext() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [InlineCode]. */ + class Builder internal constructor() { + + private var code: JsonField? = null + private var inlineContext: JsonField? = null + private var name: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(inlineCode: InlineCode) = apply { + code = inlineCode.code + inlineContext = inlineCode.inlineContext + name = inlineCode.name + additionalProperties = inlineCode.additionalProperties.toMutableMap() + } + + /** The inline code to execute */ + fun code(code: String) = code(JsonField.of(code)) + + /** + * Sets [Builder.code] to an arbitrary JSON value. + * + * You should usually call [Builder.code] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun code(code: JsonField) = apply { this.code = code } + + fun inlineContext(inlineContext: InlineContext) = + inlineContext(JsonField.of(inlineContext)) + + /** + * Sets [Builder.inlineContext] to an arbitrary JSON value. + * + * You should usually call [Builder.inlineContext] with a well-typed [InlineContext] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun inlineContext(inlineContext: JsonField) = apply { + this.inlineContext = inlineContext + } + + /** The name of the inline code function */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 [InlineCode]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .code() + * .inlineContext() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): InlineCode = + InlineCode( + checkRequired("code", code), + checkRequired("inlineContext", inlineContext), + name, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): InlineCode = apply { + if (validated) { + return@apply + } + + code() + inlineContext().validate() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (code.asKnown() == null) 0 else 1) + + (inlineContext.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + class InlineContext + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val runtime: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("runtime") + @ExcludeMissing + runtime: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(runtime, version, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 runtime(): Runtime = runtime.getRequired("runtime") + + /** + * @throws BraintrustInvalidDataException 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 version(): String = version.getRequired("version") + + /** + * Returns the raw JSON value of [runtime]. + * + * Unlike [runtime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("runtime") + @ExcludeMissing + fun _runtime(): JsonField = runtime + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version + + @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 [InlineContext]. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [InlineContext]. */ + class Builder internal constructor() { + + private var runtime: JsonField? = null + private var version: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(inlineContext: InlineContext) = apply { + runtime = inlineContext.runtime + version = inlineContext.version + additionalProperties = inlineContext.additionalProperties.toMutableMap() + } + + fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) + + /** + * Sets [Builder.runtime] to an arbitrary JSON value. + * + * You should usually call [Builder.runtime] with a well-typed [Runtime] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun runtime(runtime: JsonField) = apply { this.runtime = runtime } + + fun version(version: String) = version(JsonField.of(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun version(version: JsonField) = apply { this.version = version } + + 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 [InlineContext]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): InlineContext = + InlineContext( + checkRequired("runtime", runtime), + checkRequired("version", version), + additionalProperties.toMutableMap(), ) } - return hashCode + + private var validated: Boolean = false + + fun validate(): InlineContext = apply { + if (validated) { + return@apply + } + + runtime().validate() + version() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (runtime.asKnown()?.validity() ?: 0) + (if (version.asKnown() == null) 0 else 1) + + class Runtime + @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 { + + val NODE = of("node") + + val PYTHON = of("python") + + fun of(value: String) = Runtime(JsonField.of(value)) + } + + /** An enum containing [Runtime]'s known values. */ + enum class Known { + NODE, + PYTHON, + } + + /** + * An enum containing [Runtime]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Runtime] 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 { + NODE, + PYTHON, + /** + * An enum member indicating that [Runtime] 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) { + NODE -> Value.NODE + PYTHON -> Value.PYTHON + 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 BraintrustInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + NODE -> Known.NODE + PYTHON -> Known.PYTHON + else -> throw BraintrustInvalidDataException("Unknown Runtime: $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 BraintrustInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Runtime = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Runtime && 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 InlineContext && + runtime == other.runtime && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(runtime, version, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InlineContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InlineCode && + code == other.code && + inlineContext == other.inlineContext && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(code, inlineContext, name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InlineCode{code=$code, inlineContext=$inlineContext, name=$name, additionalProperties=$additionalProperties}" + } + + /** Inline prompt definition */ + class InlinePrompt + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val inlinePrompt: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("inline_prompt") + @ExcludeMissing + inlinePrompt: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(inlinePrompt, name, mutableMapOf()) + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun inlinePrompt(): PromptData? = inlinePrompt.getNullable("inline_prompt") + + /** + * The name of the inline prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * Returns the raw JSON value of [inlinePrompt]. + * + * Unlike [inlinePrompt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("inline_prompt") + @ExcludeMissing + fun _inlinePrompt(): JsonField = inlinePrompt + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "ProjectDatasetName{projectName=$projectName, datasetName=$datasetName, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [InlinePrompt]. + * + * The following fields are required: + * ```kotlin + * .inlinePrompt() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [InlinePrompt]. */ + class Builder internal constructor() { - private var projectName: JsonField = JsonMissing.of() - private var datasetName: JsonField = JsonMissing.of() + private var inlinePrompt: JsonField? = null + private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(projectDatasetName: ProjectDatasetName) = apply { - this.projectName = projectDatasetName.projectName - this.datasetName = projectDatasetName.datasetName - additionalProperties(projectDatasetName.additionalProperties) + internal fun from(inlinePrompt: InlinePrompt) = apply { + this.inlinePrompt = inlinePrompt.inlinePrompt + name = inlinePrompt.name + additionalProperties = inlinePrompt.additionalProperties.toMutableMap() } - fun projectName(projectName: String) = projectName(JsonField.of(projectName)) + /** The prompt, model, and its parameters */ + fun inlinePrompt(inlinePrompt: PromptData?) = + inlinePrompt(JsonField.ofNullable(inlinePrompt)) - @JsonProperty("project_name") - @ExcludeMissing - fun projectName(projectName: JsonField) = apply { - this.projectName = projectName + /** + * Sets [Builder.inlinePrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.inlinePrompt] with a well-typed [PromptData] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun inlinePrompt(inlinePrompt: JsonField) = apply { + this.inlinePrompt = inlinePrompt } - fun datasetName(datasetName: String) = datasetName(JsonField.of(datasetName)) + /** The name of the inline prompt */ + fun name(name: String?) = name(JsonField.ofNullable(name)) - @JsonProperty("dataset_name") - @ExcludeMissing - fun datasetName(datasetName: JsonField) = apply { - this.datasetName = datasetName - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -791,19 +4714,89 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): ProjectDatasetName = - ProjectDatasetName( - projectName, - datasetName, - additionalProperties.toUnmodifiable(), + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [InlinePrompt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .inlinePrompt() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): InlinePrompt = + InlinePrompt( + checkRequired("inlinePrompt", inlinePrompt), + name, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): InlinePrompt = apply { + if (validated) { + return@apply + } + + inlinePrompt()?.validate() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (inlinePrompt.asKnown()?.validity() ?: 0) + (if (name.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InlinePrompt && + inlinePrompt == other.inlinePrompt && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(inlinePrompt, name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InlinePrompt{inlinePrompt=$inlinePrompt, name=$name, additionalProperties=$additionalProperties}" } } - @JsonDeserialize(using = Score.Deserializer::class) - @JsonSerialize(using = Score.Serializer::class) - class Score + /** The function to evaluate */ + @JsonDeserialize(using = Task.Deserializer::class) + @JsonSerialize(using = Task.Serializer::class) + class Task private constructor( private val functionId: FunctionId? = null, private val projectSlug: ProjectSlug? = null, @@ -814,18 +4807,21 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - /** Function id */ fun functionId(): FunctionId? = functionId + /** Project name and slug */ fun projectSlug(): ProjectSlug? = projectSlug + /** Global function name */ fun globalFunction(): GlobalFunction? = globalFunction + /** Prompt session id */ fun promptSessionId(): PromptSessionId? = promptSessionId + /** Inline code function */ fun inlineCode(): InlineCode? = inlineCode + /** Inline prompt definition */ fun inlinePrompt(): InlinePrompt? = inlinePrompt @@ -841,22 +4837,28 @@ constructor( fun isInlinePrompt(): Boolean = inlinePrompt != null + /** Function id */ fun asFunctionId(): FunctionId = functionId.getOrThrow("functionId") + /** Project name and slug */ fun asProjectSlug(): ProjectSlug = projectSlug.getOrThrow("projectSlug") + /** Global function name */ fun asGlobalFunction(): GlobalFunction = globalFunction.getOrThrow("globalFunction") + /** Prompt session id */ fun asPromptSessionId(): PromptSessionId = promptSessionId.getOrThrow("promptSessionId") + /** Inline code function */ fun asInlineCode(): InlineCode = inlineCode.getOrThrow("inlineCode") + /** Inline prompt definition */ fun asInlinePrompt(): InlinePrompt = inlinePrompt.getOrThrow("inlinePrompt") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { functionId != null -> visitor.visitFunctionId(functionId) projectSlug != null -> visitor.visitProjectSlug(projectSlug) globalFunction != null -> visitor.visitGlobalFunction(globalFunction) @@ -865,46 +4867,96 @@ constructor( inlinePrompt != null -> visitor.visitInlinePrompt(inlinePrompt) else -> visitor.unknown(_json) } - } - fun validate(): Score = apply { - if (!validated) { - if ( - functionId == null && - projectSlug == null && - globalFunction == null && - promptSessionId == null && - inlineCode == null && - inlinePrompt == null - ) { - throw BraintrustInvalidDataException("Unknown Score: $_json") - } - functionId?.validate() - projectSlug?.validate() - globalFunction?.validate() - promptSessionId?.validate() - inlineCode?.validate() - inlinePrompt?.validate() - validated = true + private var validated: Boolean = false + + fun validate(): Task = apply { + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitFunctionId(functionId: FunctionId) { + functionId.validate() + } + + override fun visitProjectSlug(projectSlug: ProjectSlug) { + projectSlug.validate() + } + + override fun visitGlobalFunction(globalFunction: GlobalFunction) { + globalFunction.validate() + } + + override fun visitPromptSessionId(promptSessionId: PromptSessionId) { + promptSessionId.validate() + } + + override fun visitInlineCode(inlineCode: InlineCode) { + inlineCode.validate() + } + + override fun visitInlinePrompt(inlinePrompt: InlinePrompt) { + inlinePrompt.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitFunctionId(functionId: FunctionId) = functionId.validity() + + override fun visitProjectSlug(projectSlug: ProjectSlug) = projectSlug.validity() + + override fun visitGlobalFunction(globalFunction: GlobalFunction) = + globalFunction.validity() + + override fun visitPromptSessionId(promptSessionId: PromptSessionId) = + promptSessionId.validity() + + override fun visitInlineCode(inlineCode: InlineCode) = inlineCode.validity() + + override fun visitInlinePrompt(inlinePrompt: InlinePrompt) = + inlinePrompt.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Score && - this.functionId == other.functionId && - this.projectSlug == other.projectSlug && - this.globalFunction == other.globalFunction && - this.promptSessionId == other.promptSessionId && - this.inlineCode == other.inlineCode && - this.inlinePrompt == other.inlinePrompt + return other is Task && + functionId == other.functionId && + projectSlug == other.projectSlug && + globalFunction == other.globalFunction && + promptSessionId == other.promptSessionId && + inlineCode == other.inlineCode && + inlinePrompt == other.inlinePrompt } - override fun hashCode(): Int { - return Objects.hash( + override fun hashCode(): Int = + Objects.hash( functionId, projectSlug, globalFunction, @@ -912,96 +4964,125 @@ constructor( inlineCode, inlinePrompt, ) - } - override fun toString(): String { - return when { - functionId != null -> "Score{functionId=$functionId}" - projectSlug != null -> "Score{projectSlug=$projectSlug}" - globalFunction != null -> "Score{globalFunction=$globalFunction}" - promptSessionId != null -> "Score{promptSessionId=$promptSessionId}" - inlineCode != null -> "Score{inlineCode=$inlineCode}" - inlinePrompt != null -> "Score{inlinePrompt=$inlinePrompt}" - _json != null -> "Score{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Score") + override fun toString(): String = + when { + functionId != null -> "Task{functionId=$functionId}" + projectSlug != null -> "Task{projectSlug=$projectSlug}" + globalFunction != null -> "Task{globalFunction=$globalFunction}" + promptSessionId != null -> "Task{promptSessionId=$promptSessionId}" + inlineCode != null -> "Task{inlineCode=$inlineCode}" + inlinePrompt != null -> "Task{inlinePrompt=$inlinePrompt}" + _json != null -> "Task{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Task") } - } companion object { - fun ofFunctionId(functionId: FunctionId) = Score(functionId = functionId) + /** Function id */ + fun ofFunctionId(functionId: FunctionId) = Task(functionId = functionId) - fun ofProjectSlug(projectSlug: ProjectSlug) = Score(projectSlug = projectSlug) + /** Project name and slug */ + fun ofProjectSlug(projectSlug: ProjectSlug) = Task(projectSlug = projectSlug) + /** Global function name */ fun ofGlobalFunction(globalFunction: GlobalFunction) = - Score(globalFunction = globalFunction) + Task(globalFunction = globalFunction) + /** Prompt session id */ fun ofPromptSessionId(promptSessionId: PromptSessionId) = - Score(promptSessionId = promptSessionId) + Task(promptSessionId = promptSessionId) - fun ofInlineCode(inlineCode: InlineCode) = Score(inlineCode = inlineCode) + /** Inline code function */ + fun ofInlineCode(inlineCode: InlineCode) = Task(inlineCode = inlineCode) - fun ofInlinePrompt(inlinePrompt: InlinePrompt) = Score(inlinePrompt = inlinePrompt) + /** Inline prompt definition */ + fun ofInlinePrompt(inlinePrompt: InlinePrompt) = Task(inlinePrompt = inlinePrompt) } + /** An interface that defines how to map each variant of [Task] to a value of type [T]. */ interface Visitor { + /** Function id */ fun visitFunctionId(functionId: FunctionId): T + /** Project name and slug */ fun visitProjectSlug(projectSlug: ProjectSlug): T + /** Global function name */ fun visitGlobalFunction(globalFunction: GlobalFunction): T + /** Prompt session id */ fun visitPromptSessionId(promptSessionId: PromptSessionId): T + /** Inline code function */ fun visitInlineCode(inlineCode: InlineCode): T + /** Inline prompt definition */ fun visitInlinePrompt(inlinePrompt: InlinePrompt): T + /** + * Maps an unknown variant of [Task] to a value of type [T]. + * + * An instance of [Task] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Score: $json") + throw BraintrustInvalidDataException("Unknown Task: $json") } } - class Deserializer : BaseDeserializer(Score::class) { + internal class Deserializer : BaseDeserializer(Task::class) { - override fun ObjectCodec.deserialize(node: JsonNode): Score { + override fun ObjectCodec.deserialize(node: JsonNode): Task { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Score(functionId = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Score(projectSlug = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Score(globalFunction = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Score(promptSessionId = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Score(inlineCode = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Score(inlinePrompt = it, _json = json) - } - return Score(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Task(functionId = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Task(projectSlug = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Task(globalFunction = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Task(promptSessionId = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Task(inlineCode = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Task(inlinePrompt = 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 -> Task(_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() + } } } - class Serializer : BaseSerializer(Score::class) { + internal class Serializer : BaseSerializer(Task::class) { override fun serialize( - value: Score, + value: Task, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.functionId != null -> generator.writeObject(value.functionId) @@ -1011,100 +5092,112 @@ constructor( value.inlineCode != null -> generator.writeObject(value.inlineCode) value.inlinePrompt != null -> generator.writeObject(value.inlinePrompt) value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Score") + else -> throw IllegalStateException("Invalid Task") } } } /** Function id */ - @JsonDeserialize(builder = FunctionId.Builder::class) - @NoAutoDetect class FunctionId + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val functionId: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("function_id") + @ExcludeMissing + functionId: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(functionId, version, mutableMapOf()) - /** The ID of the function */ + /** + * The ID of the function + * + * @throws BraintrustInvalidDataException 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 functionId(): String = functionId.getRequired("function_id") - /** The version of the function */ + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun version(): String? = version.getNullable("version") - /** The ID of the function */ - @JsonProperty("function_id") @ExcludeMissing fun _functionId() = functionId + /** + * Returns the raw JSON value of [functionId]. + * + * Unlike [functionId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_id") + @ExcludeMissing + fun _functionId(): JsonField = functionId + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version - /** The version of the function */ - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FunctionId = apply { - if (!validated) { - functionId() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionId && - this.functionId == other.functionId && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - functionId, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "FunctionId{functionId=$functionId, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [FunctionId]. + * + * The following fields are required: + * ```kotlin + * .functionId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FunctionId]. */ + class Builder internal constructor() { - private var functionId: JsonField = JsonMissing.of() + private var functionId: JsonField? = null private var version: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(functionId: FunctionId) = apply { this.functionId = functionId.functionId - this.version = functionId.version - additionalProperties(functionId.additionalProperties) + version = functionId.version + additionalProperties = functionId.additionalProperties.toMutableMap() } /** The ID of the function */ fun functionId(functionId: String) = functionId(JsonField.of(functionId)) - /** The ID of the function */ - @JsonProperty("function_id") - @ExcludeMissing + /** + * Sets [Builder.functionId] to an arbitrary JSON value. + * + * You should usually call [Builder.functionId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun functionId(functionId: JsonField) = apply { this.functionId = functionId } @@ -1112,136 +5205,230 @@ constructor( /** The version of the function */ fun version(version: String) = version(JsonField.of(version)) - /** The version of the function */ - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FunctionId]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .functionId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionId = + FunctionId( + checkRequired("functionId", functionId), + version, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): FunctionId = apply { + if (validated) { + return@apply + } + + functionId() + version() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (functionId.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + return other is FunctionId && + functionId == other.functionId && + version == other.version && + additionalProperties == other.additionalProperties + } - fun build(): FunctionId = - FunctionId( - functionId, - version, - additionalProperties.toUnmodifiable(), - ) + private val hashCode: Int by lazy { + Objects.hash(functionId, version, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FunctionId{functionId=$functionId, version=$version, additionalProperties=$additionalProperties}" } /** Project name and slug */ - @JsonDeserialize(builder = ProjectSlug.Builder::class) - @NoAutoDetect class ProjectSlug + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val projectName: JsonField, private val slug: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("project_name") + @ExcludeMissing + projectName: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(projectName, slug, version, mutableMapOf()) - /** The name of the project containing the function */ + /** + * The name of the project containing the function + * + * @throws BraintrustInvalidDataException 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 projectName(): String = projectName.getRequired("project_name") - /** The slug of the function */ + /** + * The slug of the function + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") - /** The version of the function */ + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun version(): String? = version.getNullable("version") - /** The name of the project containing the function */ - @JsonProperty("project_name") @ExcludeMissing fun _projectName() = projectName + /** + * Returns the raw JSON value of [projectName]. + * + * Unlike [projectName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("project_name") + @ExcludeMissing + fun _projectName(): JsonField = projectName + + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug - /** The slug of the function */ - @JsonProperty("slug") @ExcludeMissing fun _slug() = slug + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version - /** The version of the function */ - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ProjectSlug = apply { - if (!validated) { - projectName() - slug() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectSlug && - this.projectName == other.projectName && - this.slug == other.slug && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - projectName, - slug, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ProjectSlug{projectName=$projectName, slug=$slug, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ProjectSlug]. + * + * The following fields are required: + * ```kotlin + * .projectName() + * .slug() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ProjectSlug]. */ + class Builder internal constructor() { - private var projectName: JsonField = JsonMissing.of() - private var slug: JsonField = JsonMissing.of() + private var projectName: JsonField? = null + private var slug: JsonField? = null private var version: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectSlug: ProjectSlug) = apply { - this.projectName = projectSlug.projectName - this.slug = projectSlug.slug - this.version = projectSlug.version - additionalProperties(projectSlug.additionalProperties) + projectName = projectSlug.projectName + slug = projectSlug.slug + version = projectSlug.version + additionalProperties = projectSlug.additionalProperties.toMutableMap() } /** The name of the project containing the function */ fun projectName(projectName: String) = projectName(JsonField.of(projectName)) - /** The name of the project containing the function */ - @JsonProperty("project_name") - @ExcludeMissing + /** + * Sets [Builder.projectName] to an arbitrary JSON value. + * + * You should usually call [Builder.projectName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun projectName(projectName: JsonField) = apply { this.projectName = projectName } @@ -1249,27 +5436,34 @@ constructor( /** The slug of the function */ fun slug(slug: String) = slug(JsonField.of(slug)) - /** The slug of the function */ - @JsonProperty("slug") - @ExcludeMissing + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun slug(slug: JsonField) = apply { this.slug = slug } /** The version of the function */ fun version(version: String) = version(JsonField.of(version)) - /** The version of the function */ - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1277,87 +5471,159 @@ constructor( 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 [ProjectSlug]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .projectName() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ProjectSlug = ProjectSlug( - projectName, - slug, + checkRequired("projectName", projectName), + checkRequired("slug", slug), version, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): ProjectSlug = apply { + if (validated) { + return@apply + } + + projectName() + slug() + version() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (projectName.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectSlug && + projectName == other.projectName && + slug == other.slug && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(projectName, slug, version, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectSlug{projectName=$projectName, slug=$slug, version=$version, additionalProperties=$additionalProperties}" } /** Global function name */ - @JsonDeserialize(builder = GlobalFunction.Builder::class) - @NoAutoDetect class GlobalFunction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val globalFunction: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("global_function") + @ExcludeMissing + globalFunction: JsonField = JsonMissing.of() + ) : this(globalFunction, mutableMapOf()) /** * The name of the global function. Currently, the global namespace includes the * functions in autoevals + * + * @throws BraintrustInvalidDataException 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 globalFunction(): String = globalFunction.getRequired("global_function") /** - * The name of the global function. Currently, the global namespace includes the - * functions in autoevals + * Returns the raw JSON value of [globalFunction]. + * + * Unlike [globalFunction], this method doesn't throw if the JSON field has an + * unexpected type. */ - @JsonProperty("global_function") @ExcludeMissing fun _globalFunction() = globalFunction - - @JsonAnyGetter + @JsonProperty("global_function") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): GlobalFunction = apply { - if (!validated) { - globalFunction() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun _globalFunction(): JsonField = globalFunction - return other is GlobalFunction && - this.globalFunction == other.globalFunction && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(globalFunction, additionalProperties) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "GlobalFunction{globalFunction=$globalFunction, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [GlobalFunction]. + * + * The following fields are required: + * ```kotlin + * .globalFunction() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [GlobalFunction]. */ + class Builder internal constructor() { - private var globalFunction: JsonField = JsonMissing.of() + private var globalFunction: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(globalFunction: GlobalFunction) = apply { this.globalFunction = globalFunction.globalFunction - additionalProperties(globalFunction.additionalProperties) + additionalProperties = globalFunction.additionalProperties.toMutableMap() } /** @@ -1368,23 +5634,23 @@ constructor( globalFunction(JsonField.of(globalFunction)) /** - * The name of the global function. Currently, the global namespace includes the - * functions in autoevals + * Sets [Builder.globalFunction] to an arbitrary JSON value. + * + * You should usually call [Builder.globalFunction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. */ - @JsonProperty("global_function") - @ExcludeMissing fun globalFunction(globalFunction: JsonField) = apply { this.globalFunction = globalFunction } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1392,149 +5658,245 @@ constructor( 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 [GlobalFunction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .globalFunction() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): GlobalFunction = - GlobalFunction(globalFunction, additionalProperties.toUnmodifiable()) + GlobalFunction( + checkRequired("globalFunction", globalFunction), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GlobalFunction = apply { + if (validated) { + return@apply + } + + globalFunction() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (globalFunction.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GlobalFunction && + globalFunction == other.globalFunction && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(globalFunction, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GlobalFunction{globalFunction=$globalFunction, additionalProperties=$additionalProperties}" } /** Prompt session id */ - @JsonDeserialize(builder = PromptSessionId.Builder::class) - @NoAutoDetect class PromptSessionId + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val promptSessionId: JsonField, private val promptSessionFunctionId: JsonField, + private val promptSessionId: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The ID of the prompt session */ - fun promptSessionId(): String = promptSessionId.getRequired("prompt_session_id") + @JsonCreator + private constructor( + @JsonProperty("prompt_session_function_id") + @ExcludeMissing + promptSessionFunctionId: JsonField = JsonMissing.of(), + @JsonProperty("prompt_session_id") + @ExcludeMissing + promptSessionId: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(promptSessionFunctionId, promptSessionId, version, mutableMapOf()) - /** The ID of the function in the prompt session */ + /** + * The ID of the function in the prompt session + * + * @throws BraintrustInvalidDataException 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 promptSessionFunctionId(): String = promptSessionFunctionId.getRequired("prompt_session_function_id") - /** The version of the function */ + /** + * The ID of the prompt session + * + * @throws BraintrustInvalidDataException 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 promptSessionId(): String = promptSessionId.getRequired("prompt_session_id") + + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun version(): String? = version.getNullable("version") - /** The ID of the prompt session */ - @JsonProperty("prompt_session_id") + /** + * Returns the raw JSON value of [promptSessionFunctionId]. + * + * Unlike [promptSessionFunctionId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("prompt_session_function_id") @ExcludeMissing - fun _promptSessionId() = promptSessionId + fun _promptSessionFunctionId(): JsonField = promptSessionFunctionId - /** The ID of the function in the prompt session */ - @JsonProperty("prompt_session_function_id") + /** + * Returns the raw JSON value of [promptSessionId]. + * + * Unlike [promptSessionId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("prompt_session_id") @ExcludeMissing - fun _promptSessionFunctionId() = promptSessionFunctionId + fun _promptSessionId(): JsonField = promptSessionId + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version - /** The version of the function */ - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): PromptSessionId = apply { - if (!validated) { - promptSessionId() - promptSessionFunctionId() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is PromptSessionId && - this.promptSessionId == other.promptSessionId && - this.promptSessionFunctionId == other.promptSessionFunctionId && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - promptSessionId, - promptSessionFunctionId, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "PromptSessionId{promptSessionId=$promptSessionId, promptSessionFunctionId=$promptSessionFunctionId, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [PromptSessionId]. + * + * The following fields are required: + * ```kotlin + * .promptSessionFunctionId() + * .promptSessionId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [PromptSessionId]. */ + class Builder internal constructor() { - private var promptSessionId: JsonField = JsonMissing.of() - private var promptSessionFunctionId: JsonField = JsonMissing.of() + private var promptSessionFunctionId: JsonField? = null + private var promptSessionId: JsonField? = null private var version: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(promptSessionId: PromptSessionId) = apply { + promptSessionFunctionId = promptSessionId.promptSessionFunctionId this.promptSessionId = promptSessionId.promptSessionId - this.promptSessionFunctionId = promptSessionId.promptSessionFunctionId - this.version = promptSessionId.version - additionalProperties(promptSessionId.additionalProperties) - } - - /** The ID of the prompt session */ - fun promptSessionId(promptSessionId: String) = - promptSessionId(JsonField.of(promptSessionId)) - - /** The ID of the prompt session */ - @JsonProperty("prompt_session_id") - @ExcludeMissing - fun promptSessionId(promptSessionId: JsonField) = apply { - this.promptSessionId = promptSessionId + version = promptSessionId.version + additionalProperties = promptSessionId.additionalProperties.toMutableMap() } /** The ID of the function in the prompt session */ fun promptSessionFunctionId(promptSessionFunctionId: String) = promptSessionFunctionId(JsonField.of(promptSessionFunctionId)) - /** The ID of the function in the prompt session */ - @JsonProperty("prompt_session_function_id") - @ExcludeMissing + /** + * Sets [Builder.promptSessionFunctionId] to an arbitrary JSON value. + * + * You should usually call [Builder.promptSessionFunctionId] with a well-typed + * [String] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun promptSessionFunctionId(promptSessionFunctionId: JsonField) = apply { this.promptSessionFunctionId = promptSessionFunctionId } + /** The ID of the prompt session */ + fun promptSessionId(promptSessionId: String) = + promptSessionId(JsonField.of(promptSessionId)) + + /** + * Sets [Builder.promptSessionId] to an arbitrary JSON value. + * + * You should usually call [Builder.promptSessionId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun promptSessionId(promptSessionId: JsonField) = apply { + this.promptSessionId = promptSessionId + } + /** The version of the function */ fun version(version: String) = version(JsonField.of(version)) - /** The version of the function */ - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1542,142 +5904,248 @@ constructor( 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 [PromptSessionId]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .promptSessionFunctionId() + * .promptSessionId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): PromptSessionId = PromptSessionId( - promptSessionId, - promptSessionFunctionId, + checkRequired("promptSessionFunctionId", promptSessionFunctionId), + checkRequired("promptSessionId", promptSessionId), version, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): PromptSessionId = apply { + if (validated) { + return@apply + } + + promptSessionFunctionId() + promptSessionId() + version() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (promptSessionFunctionId.asKnown() == null) 0 else 1) + + (if (promptSessionId.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PromptSessionId && + promptSessionFunctionId == other.promptSessionFunctionId && + promptSessionId == other.promptSessionId && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + promptSessionFunctionId, + promptSessionId, + version, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PromptSessionId{promptSessionFunctionId=$promptSessionFunctionId, promptSessionId=$promptSessionId, version=$version, additionalProperties=$additionalProperties}" } /** Inline code function */ - @JsonDeserialize(builder = InlineCode.Builder::class) - @NoAutoDetect class InlineCode + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val inlineContext: JsonField, private val code: JsonField, + private val inlineContext: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("code") @ExcludeMissing code: JsonField = JsonMissing.of(), + @JsonProperty("inline_context") + @ExcludeMissing + inlineContext: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(code, inlineContext, name, mutableMapOf()) - private var hashCode: Int = 0 + /** + * The inline code to execute + * + * @throws BraintrustInvalidDataException 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 code(): String = code.getRequired("code") + /** + * @throws BraintrustInvalidDataException 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 inlineContext(): InlineContext = inlineContext.getRequired("inline_context") - /** The inline code to execute */ - fun code(): String = code.getRequired("code") - - /** The name of the inline code function */ + /** + * The name of the inline code function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") - @JsonProperty("inline_context") @ExcludeMissing fun _inlineContext() = inlineContext + /** + * Returns the raw JSON value of [code]. + * + * Unlike [code], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("code") @ExcludeMissing fun _code(): JsonField = code + + /** + * Returns the raw JSON value of [inlineContext]. + * + * Unlike [inlineContext], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("inline_context") + @ExcludeMissing + fun _inlineContext(): JsonField = inlineContext - /** The inline code to execute */ - @JsonProperty("code") @ExcludeMissing fun _code() = code + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** The name of the inline code function */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InlineCode = apply { - if (!validated) { - inlineContext().validate() - code() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InlineCode && - this.inlineContext == other.inlineContext && - this.code == other.code && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - inlineContext, - code, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InlineCode{inlineContext=$inlineContext, code=$code, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [InlineCode]. + * + * The following fields are required: + * ```kotlin + * .code() + * .inlineContext() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [InlineCode]. */ + class Builder internal constructor() { - private var inlineContext: JsonField = JsonMissing.of() - private var code: JsonField = JsonMissing.of() + private var code: JsonField? = null + private var inlineContext: JsonField? = null private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inlineCode: InlineCode) = apply { - this.inlineContext = inlineCode.inlineContext - this.code = inlineCode.code - this.name = inlineCode.name - additionalProperties(inlineCode.additionalProperties) + code = inlineCode.code + inlineContext = inlineCode.inlineContext + name = inlineCode.name + additionalProperties = inlineCode.additionalProperties.toMutableMap() } + /** The inline code to execute */ + fun code(code: String) = code(JsonField.of(code)) + + /** + * Sets [Builder.code] to an arbitrary JSON value. + * + * You should usually call [Builder.code] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun code(code: JsonField) = apply { this.code = code } + fun inlineContext(inlineContext: InlineContext) = inlineContext(JsonField.of(inlineContext)) - @JsonProperty("inline_context") - @ExcludeMissing + /** + * Sets [Builder.inlineContext] to an arbitrary JSON value. + * + * You should usually call [Builder.inlineContext] with a well-typed [InlineContext] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ fun inlineContext(inlineContext: JsonField) = apply { this.inlineContext = inlineContext } - /** The inline code to execute */ - fun code(code: String) = code(JsonField.of(code)) - - /** The inline code to execute */ - @JsonProperty("code") - @ExcludeMissing - fun code(code: JsonField) = apply { this.code = code } - /** The name of the inline code function */ - fun name(name: String) = name(JsonField.of(name)) + fun name(name: String?) = name(JsonField.ofNullable(name)) - /** The name of the inline code function */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1685,113 +6153,186 @@ constructor( 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 [InlineCode]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .code() + * .inlineContext() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): InlineCode = InlineCode( - inlineContext, - code, + checkRequired("code", code), + checkRequired("inlineContext", inlineContext), name, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = InlineContext.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): InlineCode = apply { + if (validated) { + return@apply + } + + code() + inlineContext().validate() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (code.asKnown() == null) 0 else 1) + + (inlineContext.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + class InlineContext + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val runtime: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("runtime") + @ExcludeMissing + runtime: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(runtime, version, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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 runtime(): Runtime = runtime.getRequired("runtime") + /** + * @throws BraintrustInvalidDataException 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 version(): String = version.getRequired("version") - @JsonProperty("runtime") @ExcludeMissing fun _runtime() = runtime - - @JsonProperty("version") @ExcludeMissing fun _version() = version - - @JsonAnyGetter + /** + * Returns the raw JSON value of [runtime]. + * + * Unlike [runtime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("runtime") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _runtime(): JsonField = runtime - fun validate(): InlineContext = apply { - if (!validated) { - runtime() - version() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version - return other is InlineContext && - this.runtime == other.runtime && - this.version == other.version && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtime, - version, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "InlineContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [InlineContext]. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [InlineContext]. */ + class Builder internal constructor() { - private var runtime: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() + private var runtime: JsonField? = null + private var version: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inlineContext: InlineContext) = apply { - this.runtime = inlineContext.runtime - this.version = inlineContext.version - additionalProperties(inlineContext.additionalProperties) + runtime = inlineContext.runtime + version = inlineContext.version + additionalProperties = inlineContext.additionalProperties.toMutableMap() } fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) - @JsonProperty("runtime") - @ExcludeMissing + /** + * Sets [Builder.runtime] to an arbitrary JSON value. + * + * You should usually call [Builder.runtime] with a well-typed [Runtime] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ fun runtime(runtime: JsonField) = apply { this.runtime = runtime } fun version(version: String) = version(JsonField.of(version)) - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1799,55 +6340,120 @@ constructor( 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 [InlineContext]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): InlineContext = InlineContext( - runtime, - version, - additionalProperties.toUnmodifiable(), + checkRequired("runtime", runtime), + checkRequired("version", version), + additionalProperties.toMutableMap(), ) } - class Runtime - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): InlineContext = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + runtime().validate() + version() + validated = true + } - return other is Runtime && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (runtime.asKnown()?.validity() ?: 0) + (if (version.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Runtime + @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 { - val NODE = Runtime(JsonField.of("node")) + val NODE = of("node") - val PYTHON = Runtime(JsonField.of("python")) + val PYTHON = of("python") fun of(value: String) = Runtime(JsonField.of(value)) } + /** An enum containing [Runtime]'s known values. */ enum class Known { NODE, PYTHON, } + /** + * An enum containing [Runtime]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Runtime] 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 { NODE, PYTHON, + /** + * An enum member indicating that [Runtime] 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) { NODE -> Value.NODE @@ -1855,6 +6461,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a + * not a known member. + */ fun known(): Known = when (this) { NODE -> Known.NODE @@ -1862,121 +6477,224 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown Runtime: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Runtime = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Runtime && 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 InlineContext && + runtime == other.runtime && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(runtime, version, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InlineContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is InlineCode && + code == other.code && + inlineContext == other.inlineContext && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(code, inlineContext, name, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InlineCode{code=$code, inlineContext=$inlineContext, name=$name, additionalProperties=$additionalProperties}" } /** Inline prompt definition */ - @JsonDeserialize(builder = InlinePrompt.Builder::class) - @NoAutoDetect class InlinePrompt + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val inlinePrompt: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("inline_prompt") + @ExcludeMissing + inlinePrompt: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(inlinePrompt, name, mutableMapOf()) - /** The prompt, model, and its parameters */ + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun inlinePrompt(): PromptData? = inlinePrompt.getNullable("inline_prompt") - /** The name of the inline prompt */ + /** + * The name of the inline prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") - /** The prompt, model, and its parameters */ - @JsonProperty("inline_prompt") @ExcludeMissing fun _inlinePrompt() = inlinePrompt + /** + * Returns the raw JSON value of [inlinePrompt]. + * + * Unlike [inlinePrompt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("inline_prompt") + @ExcludeMissing + fun _inlinePrompt(): JsonField = inlinePrompt + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** The name of the inline prompt */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InlinePrompt = apply { - if (!validated) { - inlinePrompt()?.validate() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InlinePrompt && - this.inlinePrompt == other.inlinePrompt && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - inlinePrompt, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InlinePrompt{inlinePrompt=$inlinePrompt, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [InlinePrompt]. + * + * The following fields are required: + * ```kotlin + * .inlinePrompt() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [InlinePrompt]. */ + class Builder internal constructor() { - private var inlinePrompt: JsonField = JsonMissing.of() + private var inlinePrompt: JsonField? = null private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inlinePrompt: InlinePrompt) = apply { this.inlinePrompt = inlinePrompt.inlinePrompt - this.name = inlinePrompt.name - additionalProperties(inlinePrompt.additionalProperties) + name = inlinePrompt.name + additionalProperties = inlinePrompt.additionalProperties.toMutableMap() } /** The prompt, model, and its parameters */ - fun inlinePrompt(inlinePrompt: PromptData) = - inlinePrompt(JsonField.of(inlinePrompt)) + fun inlinePrompt(inlinePrompt: PromptData?) = + inlinePrompt(JsonField.ofNullable(inlinePrompt)) - /** The prompt, model, and its parameters */ - @JsonProperty("inline_prompt") - @ExcludeMissing + /** + * Sets [Builder.inlinePrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.inlinePrompt] with a well-typed [PromptData] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ fun inlinePrompt(inlinePrompt: JsonField) = apply { this.inlinePrompt = inlinePrompt } /** The name of the inline prompt */ - fun name(name: String) = name(JsonField.of(name)) + fun name(name: String?) = name(JsonField.ofNullable(name)) - /** The name of the inline prompt */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1984,893 +6702,1074 @@ constructor( 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 [InlinePrompt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .inlinePrompt() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): InlinePrompt = InlinePrompt( - inlinePrompt, + checkRequired("inlinePrompt", inlinePrompt), name, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - } - } - @JsonDeserialize(using = Task.Deserializer::class) - @JsonSerialize(using = Task.Serializer::class) - class Task - private constructor( - private val functionId: FunctionId? = null, - private val projectSlug: ProjectSlug? = null, - private val globalFunction: GlobalFunction? = null, - private val promptSessionId: PromptSessionId? = null, - private val inlineCode: InlineCode? = null, - private val inlinePrompt: InlinePrompt? = null, - private val _json: JsonValue? = null, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): InlinePrompt = apply { + if (validated) { + return@apply + } - /** Function id */ - fun functionId(): FunctionId? = functionId - /** Project name and slug */ - fun projectSlug(): ProjectSlug? = projectSlug - /** Global function name */ - fun globalFunction(): GlobalFunction? = globalFunction - /** Prompt session id */ - fun promptSessionId(): PromptSessionId? = promptSessionId - /** Inline code function */ - fun inlineCode(): InlineCode? = inlineCode - /** Inline prompt definition */ - fun inlinePrompt(): InlinePrompt? = inlinePrompt + inlinePrompt()?.validate() + name() + validated = true + } - fun isFunctionId(): Boolean = functionId != null + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun isProjectSlug(): Boolean = projectSlug != null + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (inlinePrompt.asKnown()?.validity() ?: 0) + (if (name.asKnown() == null) 0 else 1) - fun isGlobalFunction(): Boolean = globalFunction != null + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun isPromptSessionId(): Boolean = promptSessionId != null + return other is InlinePrompt && + inlinePrompt == other.inlinePrompt && + name == other.name && + additionalProperties == other.additionalProperties + } - fun isInlineCode(): Boolean = inlineCode != null + private val hashCode: Int by lazy { + Objects.hash(inlinePrompt, name, additionalProperties) + } - fun isInlinePrompt(): Boolean = inlinePrompt != null + override fun hashCode(): Int = hashCode - fun asFunctionId(): FunctionId = functionId.getOrThrow("functionId") + override fun toString() = + "InlinePrompt{inlinePrompt=$inlinePrompt, name=$name, additionalProperties=$additionalProperties}" + } + } - fun asProjectSlug(): ProjectSlug = projectSlug.getOrThrow("projectSlug") + /** + * Optional settings for collecting git metadata. By default, will collect all git metadata + * fields allowed in org-level settings. + */ + class GitMetadataSettings + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val collect: JsonField, + private val fields: JsonField>, + private val additionalProperties: MutableMap, + ) { - fun asGlobalFunction(): GlobalFunction = globalFunction.getOrThrow("globalFunction") + @JsonCreator + private constructor( + @JsonProperty("collect") @ExcludeMissing collect: JsonField = JsonMissing.of(), + @JsonProperty("fields") + @ExcludeMissing + fields: JsonField> = JsonMissing.of(), + ) : this(collect, fields, mutableMapOf()) - fun asPromptSessionId(): PromptSessionId = promptSessionId.getOrThrow("promptSessionId") + /** + * @throws BraintrustInvalidDataException 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 collect(): Collect = collect.getRequired("collect") - fun asInlineCode(): InlineCode = inlineCode.getOrThrow("inlineCode") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun fields(): List? = fields.getNullable("fields") - fun asInlinePrompt(): InlinePrompt = inlinePrompt.getOrThrow("inlinePrompt") + /** + * Returns the raw JSON value of [collect]. + * + * Unlike [collect], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("collect") @ExcludeMissing fun _collect(): JsonField = collect - fun _json(): JsonValue? = _json + /** + * Returns the raw JSON value of [fields]. + * + * Unlike [fields], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("fields") @ExcludeMissing fun _fields(): JsonField> = fields - fun accept(visitor: Visitor): T { - return when { - functionId != null -> visitor.visitFunctionId(functionId) - projectSlug != null -> visitor.visitProjectSlug(projectSlug) - globalFunction != null -> visitor.visitGlobalFunction(globalFunction) - promptSessionId != null -> visitor.visitPromptSessionId(promptSessionId) - inlineCode != null -> visitor.visitInlineCode(inlineCode) - inlinePrompt != null -> visitor.visitInlinePrompt(inlinePrompt) - else -> visitor.unknown(_json) - } + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun validate(): Task = apply { - if (!validated) { - if ( - functionId == null && - projectSlug == null && - globalFunction == null && - promptSessionId == null && - inlineCode == null && - inlinePrompt == null - ) { - throw BraintrustInvalidDataException("Unknown Task: $_json") - } - functionId?.validate() - projectSlug?.validate() - globalFunction?.validate() - promptSessionId?.validate() - inlineCode?.validate() - inlinePrompt?.validate() - validated = true - } - } + @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 Task && - this.functionId == other.functionId && - this.projectSlug == other.projectSlug && - this.globalFunction == other.globalFunction && - this.promptSessionId == other.promptSessionId && - this.inlineCode == other.inlineCode && - this.inlinePrompt == other.inlinePrompt - } + companion object { - override fun hashCode(): Int { - return Objects.hash( - functionId, - projectSlug, - globalFunction, - promptSessionId, - inlineCode, - inlinePrompt, - ) + /** + * Returns a mutable builder for constructing an instance of [GitMetadataSettings]. + * + * The following fields are required: + * ```kotlin + * .collect() + * ``` + */ + fun builder() = Builder() } - override fun toString(): String { - return when { - functionId != null -> "Task{functionId=$functionId}" - projectSlug != null -> "Task{projectSlug=$projectSlug}" - globalFunction != null -> "Task{globalFunction=$globalFunction}" - promptSessionId != null -> "Task{promptSessionId=$promptSessionId}" - inlineCode != null -> "Task{inlineCode=$inlineCode}" - inlinePrompt != null -> "Task{inlinePrompt=$inlinePrompt}" - _json != null -> "Task{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Task") - } - } + /** A builder for [GitMetadataSettings]. */ + class Builder internal constructor() { - companion object { + private var collect: JsonField? = null + private var fields: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun ofFunctionId(functionId: FunctionId) = Task(functionId = functionId) + internal fun from(gitMetadataSettings: GitMetadataSettings) = apply { + collect = gitMetadataSettings.collect + fields = gitMetadataSettings.fields.map { it.toMutableList() } + additionalProperties = gitMetadataSettings.additionalProperties.toMutableMap() + } - fun ofProjectSlug(projectSlug: ProjectSlug) = Task(projectSlug = projectSlug) + fun collect(collect: Collect) = collect(JsonField.of(collect)) - fun ofGlobalFunction(globalFunction: GlobalFunction) = - Task(globalFunction = globalFunction) + /** + * Sets [Builder.collect] to an arbitrary JSON value. + * + * You should usually call [Builder.collect] with a well-typed [Collect] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun collect(collect: JsonField) = apply { this.collect = collect } - fun ofPromptSessionId(promptSessionId: PromptSessionId) = - Task(promptSessionId = promptSessionId) + fun fields(fields: List) = fields(JsonField.of(fields)) - fun ofInlineCode(inlineCode: InlineCode) = Task(inlineCode = inlineCode) + /** + * Sets [Builder.fields] to an arbitrary JSON value. + * + * You should usually call [Builder.fields] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun fields(fields: JsonField>) = apply { + this.fields = fields.map { it.toMutableList() } + } - fun ofInlinePrompt(inlinePrompt: InlinePrompt) = Task(inlinePrompt = inlinePrompt) - } + /** + * Adds a single [Field] to [fields]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addField(field: Field) = apply { + fields = + (fields ?: JsonField.of(mutableListOf())).also { + checkKnown("fields", it).add(field) + } + } - interface Visitor { + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun visitFunctionId(functionId: FunctionId): T + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun visitProjectSlug(projectSlug: ProjectSlug): T + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun visitGlobalFunction(globalFunction: GlobalFunction): T + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun visitPromptSessionId(promptSessionId: PromptSessionId): T + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun visitInlineCode(inlineCode: InlineCode): T + /** + * Returns an immutable instance of [GitMetadataSettings]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .collect() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GitMetadataSettings = + GitMetadataSettings( + checkRequired("collect", collect), + (fields ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } - fun visitInlinePrompt(inlinePrompt: InlinePrompt): T + private var validated: Boolean = false - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Task: $json") + fun validate(): GitMetadataSettings = apply { + if (validated) { + return@apply } + + collect().validate() + fields()?.forEach { it.validate() } + validated = true } - class Deserializer : BaseDeserializer(Task::class) { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - override fun ObjectCodec.deserialize(node: JsonNode): Task { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Task(functionId = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Task(projectSlug = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Task(globalFunction = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Task(promptSessionId = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Task(inlineCode = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Task(inlinePrompt = it, _json = json) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (collect.asKnown()?.validity() ?: 0) + + (fields.asKnown()?.sumOf { it.validity().toInt() } ?: 0) - return Task(_json = json) - } - } + class Collect @JsonCreator private constructor(private val value: JsonField) : + Enum { - class Serializer : BaseSerializer(Task::class) { + /** + * 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 - override fun serialize( - value: Task, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.functionId != null -> generator.writeObject(value.functionId) - value.projectSlug != null -> generator.writeObject(value.projectSlug) - value.globalFunction != null -> generator.writeObject(value.globalFunction) - value.promptSessionId != null -> generator.writeObject(value.promptSessionId) - value.inlineCode != null -> generator.writeObject(value.inlineCode) - value.inlinePrompt != null -> generator.writeObject(value.inlinePrompt) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Task") - } - } - } + companion object { - /** Function id */ - @JsonDeserialize(builder = FunctionId.Builder::class) - @NoAutoDetect - class FunctionId - private constructor( - private val functionId: JsonField, - private val version: JsonField, - private val additionalProperties: Map, - ) { + val ALL = of("all") - private var validated: Boolean = false + val NONE = of("none") - private var hashCode: Int = 0 + val SOME = of("some") - /** The ID of the function */ - fun functionId(): String = functionId.getRequired("function_id") + fun of(value: String) = Collect(JsonField.of(value)) + } - /** The version of the function */ - fun version(): String? = version.getNullable("version") + /** An enum containing [Collect]'s known values. */ + enum class Known { + ALL, + NONE, + SOME, + } + + /** + * An enum containing [Collect]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Collect] 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 { + ALL, + NONE, + SOME, + /** + * An enum member indicating that [Collect] 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) { + ALL -> Value.ALL + NONE -> Value.NONE + SOME -> Value.SOME + else -> Value._UNKNOWN + } - /** The ID of the function */ - @JsonProperty("function_id") @ExcludeMissing fun _functionId() = functionId + /** + * 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + ALL -> Known.ALL + NONE -> Known.NONE + SOME -> Known.SOME + else -> throw BraintrustInvalidDataException("Unknown Collect: $value") + } - /** The version of the function */ - @JsonProperty("version") @ExcludeMissing fun _version() = version + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + private var validated: Boolean = false - fun validate(): FunctionId = apply { - if (!validated) { - functionId() - version() - validated = true + fun validate(): Collect = apply { + if (validated) { + return@apply } + + known() + validated = true } - fun toBuilder() = Builder().from(this) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FunctionId && - this.functionId == other.functionId && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - functionId, - version, - additionalProperties, - ) - } - return hashCode + return other is Collect && value == other.value } - override fun toString() = - "FunctionId{functionId=$functionId, version=$version, additionalProperties=$additionalProperties}" - - companion object { + override fun hashCode() = value.hashCode() - fun builder() = Builder() - } + override fun toString() = value.toString() + } - class Builder { + class Field @JsonCreator private constructor(private val value: JsonField) : Enum { - private var functionId: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + /** + * 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 - internal fun from(functionId: FunctionId) = apply { - this.functionId = functionId.functionId - this.version = functionId.version - additionalProperties(functionId.additionalProperties) - } + companion object { - /** The ID of the function */ - fun functionId(functionId: String) = functionId(JsonField.of(functionId)) + val COMMIT = of("commit") - /** The ID of the function */ - @JsonProperty("function_id") - @ExcludeMissing - fun functionId(functionId: JsonField) = apply { - this.functionId = functionId - } + val BRANCH = of("branch") - /** The version of the function */ - fun version(version: String) = version(JsonField.of(version)) + val TAG = of("tag") - /** The version of the function */ - @JsonProperty("version") - @ExcludeMissing - fun version(version: JsonField) = apply { this.version = version } + val DIRTY = of("dirty") - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + val AUTHOR_NAME = of("author_name") - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + val AUTHOR_EMAIL = of("author_email") - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + val COMMIT_MESSAGE = of("commit_message") - fun build(): FunctionId = - FunctionId( - functionId, - version, - additionalProperties.toUnmodifiable(), - ) - } - } + val COMMIT_TIME = of("commit_time") - /** Project name and slug */ - @JsonDeserialize(builder = ProjectSlug.Builder::class) - @NoAutoDetect - class ProjectSlug - private constructor( - private val projectName: JsonField, - private val slug: JsonField, - private val version: JsonField, - private val additionalProperties: Map, - ) { + val GIT_DIFF = of("git_diff") - private var validated: Boolean = false + fun of(value: String) = Field(JsonField.of(value)) + } - private var hashCode: Int = 0 + /** An enum containing [Field]'s known values. */ + enum class Known { + COMMIT, + BRANCH, + TAG, + DIRTY, + AUTHOR_NAME, + AUTHOR_EMAIL, + COMMIT_MESSAGE, + COMMIT_TIME, + GIT_DIFF, + } - /** The name of the project containing the function */ - fun projectName(): String = projectName.getRequired("project_name") + /** + * An enum containing [Field]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Field] 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 { + COMMIT, + BRANCH, + TAG, + DIRTY, + AUTHOR_NAME, + AUTHOR_EMAIL, + COMMIT_MESSAGE, + COMMIT_TIME, + GIT_DIFF, + /** + * An enum member indicating that [Field] was instantiated with an unknown value. + */ + _UNKNOWN, + } - /** The slug of the function */ - fun slug(): String = slug.getRequired("slug") + /** + * 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) { + COMMIT -> Value.COMMIT + BRANCH -> Value.BRANCH + TAG -> Value.TAG + DIRTY -> Value.DIRTY + AUTHOR_NAME -> Value.AUTHOR_NAME + AUTHOR_EMAIL -> Value.AUTHOR_EMAIL + COMMIT_MESSAGE -> Value.COMMIT_MESSAGE + COMMIT_TIME -> Value.COMMIT_TIME + GIT_DIFF -> Value.GIT_DIFF + else -> Value._UNKNOWN + } - /** The version of the function */ - fun version(): String? = version.getNullable("version") + /** + * 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + COMMIT -> Known.COMMIT + BRANCH -> Known.BRANCH + TAG -> Known.TAG + DIRTY -> Known.DIRTY + AUTHOR_NAME -> Known.AUTHOR_NAME + AUTHOR_EMAIL -> Known.AUTHOR_EMAIL + COMMIT_MESSAGE -> Known.COMMIT_MESSAGE + COMMIT_TIME -> Known.COMMIT_TIME + GIT_DIFF -> Known.GIT_DIFF + else -> throw BraintrustInvalidDataException("Unknown Field: $value") + } - /** The name of the project containing the function */ - @JsonProperty("project_name") @ExcludeMissing fun _projectName() = projectName + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") - /** The slug of the function */ - @JsonProperty("slug") @ExcludeMissing fun _slug() = slug + private var validated: Boolean = false - /** The version of the function */ - @JsonProperty("version") @ExcludeMissing fun _version() = version + fun validate(): Field = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + known() + validated = true + } - fun validate(): ProjectSlug = apply { - if (!validated) { - projectName() - slug() - version() - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ProjectSlug && - this.projectName == other.projectName && - this.slug == other.slug && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - projectName, - slug, - version, - additionalProperties, - ) - } - return hashCode + return other is Field && value == other.value } - override fun toString() = - "ProjectSlug{projectName=$projectName, slug=$slug, version=$version, additionalProperties=$additionalProperties}" + override fun hashCode() = value.hashCode() - companion object { + override fun toString() = value.toString() + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { + return other is GitMetadataSettings && + collect == other.collect && + fields == other.fields && + additionalProperties == other.additionalProperties + } - private var projectName: JsonField = JsonMissing.of() - private var slug: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + private val hashCode: Int by lazy { Objects.hash(collect, fields, additionalProperties) } - internal fun from(projectSlug: ProjectSlug) = apply { - this.projectName = projectSlug.projectName - this.slug = projectSlug.slug - this.version = projectSlug.version - additionalProperties(projectSlug.additionalProperties) - } + override fun hashCode(): Int = hashCode - /** The name of the project containing the function */ - fun projectName(projectName: String) = projectName(JsonField.of(projectName)) + override fun toString() = + "GitMetadataSettings{collect=$collect, fields=$fields, additionalProperties=$additionalProperties}" + } - /** The name of the project containing the function */ - @JsonProperty("project_name") - @ExcludeMissing - fun projectName(projectName: JsonField) = apply { - this.projectName = projectName - } + /** + * Optional experiment-level metadata to store about the evaluation. You can later use this to + * slice & dice across experiments. + */ + class Metadata + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { - /** The slug of the function */ - fun slug(slug: String) = slug(JsonField.of(slug)) + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties - /** The slug of the function */ - @JsonProperty("slug") - @ExcludeMissing - fun slug(slug: JsonField) = apply { this.slug = slug } + fun toBuilder() = Builder().from(this) - /** The version of the function */ - fun version(version: String) = version(JsonField.of(version)) + companion object { - /** The version of the function */ - @JsonProperty("version") - @ExcludeMissing - fun version(version: JsonField) = apply { this.version = version } + /** Returns a mutable builder for constructing an instance of [Metadata]. */ + fun builder() = Builder() + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + /** A builder for [Metadata]. */ + class Builder internal constructor() { - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + private var additionalProperties: MutableMap = mutableMapOf() - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + internal fun from(metadata: Metadata) = apply { + additionalProperties = metadata.additionalProperties.toMutableMap() + } - fun build(): ProjectSlug = - ProjectSlug( - projectName, - slug, - version, - additionalProperties.toUnmodifiable(), - ) + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } - } - /** Global function name */ - @JsonDeserialize(builder = GlobalFunction.Builder::class) - @NoAutoDetect - class GlobalFunction - private constructor( - private val globalFunction: JsonField, - private val additionalProperties: Map, - ) { + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - private var validated: Boolean = false + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - private var hashCode: Int = 0 + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - /** - * The name of the global function. Currently, the global namespace includes the - * functions in autoevals - */ - fun globalFunction(): String = globalFunction.getRequired("global_function") + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } /** - * The name of the global function. Currently, the global namespace includes the - * functions in autoevals + * Returns an immutable instance of [Metadata]. + * + * Further updates to this [Builder] will not mutate the returned instance. */ - @JsonProperty("global_function") @ExcludeMissing fun _globalFunction() = globalFunction + fun build(): Metadata = Metadata(additionalProperties.toImmutable()) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + private var validated: Boolean = false - fun validate(): GlobalFunction = apply { - if (!validated) { - globalFunction() - validated = true - } + fun validate(): Metadata = apply { + if (validated) { + return@apply } - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GlobalFunction && - this.globalFunction == other.globalFunction && - this.additionalProperties == other.additionalProperties - } + validated = true + } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(globalFunction, additionalProperties) - } - return hashCode + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun toString() = - "GlobalFunction{globalFunction=$globalFunction, additionalProperties=$additionalProperties}" - - companion object { + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var globalFunction: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(globalFunction: GlobalFunction) = apply { - this.globalFunction = globalFunction.globalFunction - additionalProperties(globalFunction.additionalProperties) - } - - /** - * The name of the global function. Currently, the global namespace includes the - * functions in autoevals - */ - fun globalFunction(globalFunction: String) = - globalFunction(JsonField.of(globalFunction)) - - /** - * The name of the global function. Currently, the global namespace includes the - * functions in autoevals - */ - @JsonProperty("global_function") - @ExcludeMissing - fun globalFunction(globalFunction: JsonField) = apply { - this.globalFunction = globalFunction - } + return other is Metadata && additionalProperties == other.additionalProperties + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + override fun hashCode(): Int = hashCode - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + } - fun build(): GlobalFunction = - GlobalFunction(globalFunction, additionalProperties.toUnmodifiable()) - } - } + /** Options for tracing the evaluation */ + @JsonDeserialize(using = Parent.Deserializer::class) + @JsonSerialize(using = Parent.Serializer::class) + class Parent + private constructor( + private val spanParentStruct: SpanParentStruct? = null, + private val string: String? = null, + private val _json: JsonValue? = null, + ) { - /** Prompt session id */ - @JsonDeserialize(builder = PromptSessionId.Builder::class) - @NoAutoDetect - class PromptSessionId - private constructor( - private val promptSessionId: JsonField, - private val promptSessionFunctionId: JsonField, - private val version: JsonField, - private val additionalProperties: Map, - ) { + /** Span parent properties */ + fun spanParentStruct(): SpanParentStruct? = spanParentStruct - private var validated: Boolean = false + /** The parent's span identifier, created by calling `.export()` on a span */ + fun string(): String? = string - private var hashCode: Int = 0 + fun isSpanParentStruct(): Boolean = spanParentStruct != null - /** The ID of the prompt session */ - fun promptSessionId(): String = promptSessionId.getRequired("prompt_session_id") + fun isString(): Boolean = string != null - /** The ID of the function in the prompt session */ - fun promptSessionFunctionId(): String = - promptSessionFunctionId.getRequired("prompt_session_function_id") + /** Span parent properties */ + fun asSpanParentStruct(): SpanParentStruct = spanParentStruct.getOrThrow("spanParentStruct") - /** The version of the function */ - fun version(): String? = version.getNullable("version") + /** The parent's span identifier, created by calling `.export()` on a span */ + fun asString(): String = string.getOrThrow("string") - /** The ID of the prompt session */ - @JsonProperty("prompt_session_id") - @ExcludeMissing - fun _promptSessionId() = promptSessionId + fun _json(): JsonValue? = _json - /** The ID of the function in the prompt session */ - @JsonProperty("prompt_session_function_id") - @ExcludeMissing - fun _promptSessionFunctionId() = promptSessionFunctionId + fun accept(visitor: Visitor): T = + when { + spanParentStruct != null -> visitor.visitSpanParentStruct(spanParentStruct) + string != null -> visitor.visitString(string) + else -> visitor.unknown(_json) + } - /** The version of the function */ - @JsonProperty("version") @ExcludeMissing fun _version() = version + private var validated: Boolean = false - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun validate(): Parent = apply { + if (validated) { + return@apply + } - fun validate(): PromptSessionId = apply { - if (!validated) { - promptSessionId() - promptSessionFunctionId() - version() - validated = true + accept( + object : Visitor { + override fun visitSpanParentStruct(spanParentStruct: SpanParentStruct) { + spanParentStruct.validate() + } + + override fun visitString(string: String) {} } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitSpanParentStruct(spanParentStruct: SpanParentStruct) = + spanParentStruct.validity() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + override fun visitString(string: String) = 1 - return other is PromptSessionId && - this.promptSessionId == other.promptSessionId && - this.promptSessionFunctionId == other.promptSessionFunctionId && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - promptSessionId, - promptSessionFunctionId, - version, - additionalProperties, - ) + override fun unknown(json: JsonValue?) = 0 } - return hashCode + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - override fun toString() = - "PromptSessionId{promptSessionId=$promptSessionId, promptSessionFunctionId=$promptSessionFunctionId, version=$version, additionalProperties=$additionalProperties}" + return other is Parent && + spanParentStruct == other.spanParentStruct && + string == other.string + } - companion object { + override fun hashCode(): Int = Objects.hash(spanParentStruct, string) - fun builder() = Builder() + override fun toString(): String = + when { + spanParentStruct != null -> "Parent{spanParentStruct=$spanParentStruct}" + string != null -> "Parent{string=$string}" + _json != null -> "Parent{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Parent") } - class Builder { - - private var promptSessionId: JsonField = JsonMissing.of() - private var promptSessionFunctionId: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + companion object { - internal fun from(promptSessionId: PromptSessionId) = apply { - this.promptSessionId = promptSessionId.promptSessionId - this.promptSessionFunctionId = promptSessionId.promptSessionFunctionId - this.version = promptSessionId.version - additionalProperties(promptSessionId.additionalProperties) - } + /** Span parent properties */ + fun ofSpanParentStruct(spanParentStruct: SpanParentStruct) = + Parent(spanParentStruct = spanParentStruct) - /** The ID of the prompt session */ - fun promptSessionId(promptSessionId: String) = - promptSessionId(JsonField.of(promptSessionId)) + /** The parent's span identifier, created by calling `.export()` on a span */ + fun ofString(string: String) = Parent(string = string) + } - /** The ID of the prompt session */ - @JsonProperty("prompt_session_id") - @ExcludeMissing - fun promptSessionId(promptSessionId: JsonField) = apply { - this.promptSessionId = promptSessionId - } + /** An interface that defines how to map each variant of [Parent] to a value of type [T]. */ + interface Visitor { - /** The ID of the function in the prompt session */ - fun promptSessionFunctionId(promptSessionFunctionId: String) = - promptSessionFunctionId(JsonField.of(promptSessionFunctionId)) + /** Span parent properties */ + fun visitSpanParentStruct(spanParentStruct: SpanParentStruct): T - /** The ID of the function in the prompt session */ - @JsonProperty("prompt_session_function_id") - @ExcludeMissing - fun promptSessionFunctionId(promptSessionFunctionId: JsonField) = apply { - this.promptSessionFunctionId = promptSessionFunctionId - } + /** The parent's span identifier, created by calling `.export()` on a span */ + fun visitString(string: String): T - /** The version of the function */ - fun version(version: String) = version(JsonField.of(version)) + /** + * Maps an unknown variant of [Parent] to a value of type [T]. + * + * An instance of [Parent] 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 BraintrustInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("Unknown Parent: $json") + } + } - /** The version of the function */ - @JsonProperty("version") - @ExcludeMissing - fun version(version: JsonField) = apply { this.version = version } + internal class Deserializer : BaseDeserializer(Parent::class) { - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + override fun ObjectCodec.deserialize(node: JsonNode): Parent { + val json = JsonValue.fromJsonNode(node) - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Parent(spanParentStruct = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Parent(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 -> Parent(_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 putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + internal class Serializer : BaseSerializer(Parent::class) { - fun build(): PromptSessionId = - PromptSessionId( - promptSessionId, - promptSessionFunctionId, - version, - additionalProperties.toUnmodifiable(), - ) + override fun serialize( + value: Parent, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.spanParentStruct != null -> generator.writeObject(value.spanParentStruct) + value.string != null -> generator.writeObject(value.string) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Parent") + } } } - /** Inline code function */ - @JsonDeserialize(builder = InlineCode.Builder::class) - @NoAutoDetect - class InlineCode + /** Span parent properties */ + class SpanParentStruct + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val inlineContext: JsonField, - private val code: JsonField, - private val name: JsonField, - private val additionalProperties: Map, + private val objectId: JsonField, + private val objectType: JsonField, + private val propagatedEvent: JsonField, + private val rowIds: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun inlineContext(): InlineContext = inlineContext.getRequired("inline_context") + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("propagated_event") + @ExcludeMissing + propagatedEvent: JsonField = JsonMissing.of(), + @JsonProperty("row_ids") + @ExcludeMissing + rowIds: JsonField = JsonMissing.of(), + ) : this(objectId, objectType, propagatedEvent, rowIds, mutableMapOf()) - /** The inline code to execute */ - fun code(): String = code.getRequired("code") + /** + * The id of the container object you are logging to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** The name of the inline code function */ - fun name(): String? = name.getNullable("name") + /** + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = objectType.getRequired("object_type") - @JsonProperty("inline_context") @ExcludeMissing fun _inlineContext() = inlineContext + /** + * Include these properties in every span created under this parent + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun propagatedEvent(): PropagatedEvent? = + propagatedEvent.getNullable("propagated_event") - /** The inline code to execute */ - @JsonProperty("code") @ExcludeMissing fun _code() = code + /** + * Identifiers for the row to to log a subspan under + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun rowIds(): RowIds? = rowIds.getNullable("row_ids") - /** The name of the inline code function */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - @JsonAnyGetter + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("object_type") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InlineCode = apply { - if (!validated) { - inlineContext().validate() - code() - name() - validated = true - } - } + fun _objectType(): JsonField = objectType - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [propagatedEvent]. + * + * Unlike [propagatedEvent], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("propagated_event") + @ExcludeMissing + fun _propagatedEvent(): JsonField = propagatedEvent - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [rowIds]. + * + * Unlike [rowIds], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("row_ids") @ExcludeMissing fun _rowIds(): JsonField = rowIds - return other is InlineCode && - this.inlineContext == other.inlineContext && - this.code == other.code && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - inlineContext, - code, - name, - additionalProperties, - ) - } - return hashCode + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "InlineCode{inlineContext=$inlineContext, code=$code, name=$name, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [SpanParentStruct]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [SpanParentStruct]. */ + class Builder internal constructor() { - private var inlineContext: JsonField = JsonMissing.of() - private var code: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var propagatedEvent: JsonField = JsonMissing.of() + private var rowIds: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(inlineCode: InlineCode) = apply { - this.inlineContext = inlineCode.inlineContext - this.code = inlineCode.code - this.name = inlineCode.name - additionalProperties(inlineCode.additionalProperties) + internal fun from(spanParentStruct: SpanParentStruct) = apply { + objectId = spanParentStruct.objectId + objectType = spanParentStruct.objectType + propagatedEvent = spanParentStruct.propagatedEvent + rowIds = spanParentStruct.rowIds + additionalProperties = spanParentStruct.additionalProperties.toMutableMap() } - fun inlineContext(inlineContext: InlineContext) = - inlineContext(JsonField.of(inlineContext)) + /** The id of the container object you are logging to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - @JsonProperty("inline_context") - @ExcludeMissing - fun inlineContext(inlineContext: JsonField) = apply { - this.inlineContext = inlineContext + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + + fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType } - /** The inline code to execute */ - fun code(code: String) = code(JsonField.of(code)) + /** Include these properties in every span created under this parent */ + fun propagatedEvent(propagatedEvent: PropagatedEvent?) = + propagatedEvent(JsonField.ofNullable(propagatedEvent)) - /** The inline code to execute */ - @JsonProperty("code") - @ExcludeMissing - fun code(code: JsonField) = apply { this.code = code } + /** + * Sets [Builder.propagatedEvent] to an arbitrary JSON value. + * + * You should usually call [Builder.propagatedEvent] with a well-typed + * [PropagatedEvent] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun propagatedEvent(propagatedEvent: JsonField) = apply { + this.propagatedEvent = propagatedEvent + } - /** The name of the inline code function */ - fun name(name: String) = name(JsonField.of(name)) + /** Identifiers for the row to to log a subspan under */ + fun rowIds(rowIds: RowIds?) = rowIds(JsonField.ofNullable(rowIds)) - /** The name of the inline code function */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + /** + * Sets [Builder.rowIds] to an arbitrary JSON value. + * + * You should usually call [Builder.rowIds] with a well-typed [RowIds] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun rowIds(rowIds: JsonField) = apply { this.rowIds = rowIds } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2878,113 +7777,246 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): InlineCode = - InlineCode( - inlineContext, - code, - name, - additionalProperties.toUnmodifiable(), + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SpanParentStruct]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanParentStruct = + SpanParentStruct( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + propagatedEvent, + rowIds, + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = InlineContext.Builder::class) - @NoAutoDetect - class InlineContext - private constructor( - private val runtime: JsonField, - private val version: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): SpanParentStruct = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + objectId() + objectType().validate() + propagatedEvent()?.validate() + rowIds()?.validate() + validated = true + } - fun runtime(): Runtime = runtime.getRequired("runtime") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun version(): String = version.getRequired("version") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (propagatedEvent.asKnown()?.validity() ?: 0) + + (rowIds.asKnown()?.validity() ?: 0) - @JsonProperty("runtime") @ExcludeMissing fun _runtime() = runtime + class ObjectType + @JsonCreator + private constructor(private val value: JsonField) : Enum { - @JsonProperty("version") @ExcludeMissing fun _version() = version + /** + * 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 - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + companion object { - fun validate(): InlineContext = apply { - if (!validated) { - runtime() - version() - validated = true + val PROJECT_LOGS = of("project_logs") + + val EXPERIMENT = of("experiment") + + val PLAYGROUND_LOGS = of("playground_logs") + + fun of(value: String) = ObjectType(JsonField.of(value)) + } + + /** An enum containing [ObjectType]'s known values. */ + enum class Known { + PROJECT_LOGS, + EXPERIMENT, + PLAYGROUND_LOGS, + } + + /** + * An enum containing [ObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ObjectType] 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 { + PROJECT_LOGS, + EXPERIMENT, + PLAYGROUND_LOGS, + /** + * An enum member indicating that [ObjectType] 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) { + PROJECT_LOGS -> Value.PROJECT_LOGS + EXPERIMENT -> Value.EXPERIMENT + PLAYGROUND_LOGS -> Value.PLAYGROUND_LOGS + 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + PROJECT_LOGS -> Known.PROJECT_LOGS + EXPERIMENT -> Known.EXPERIMENT + PLAYGROUND_LOGS -> Known.PLAYGROUND_LOGS + else -> throw BraintrustInvalidDataException("Unknown ObjectType: $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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ObjectType = apply { + if (validated) { + return@apply } + + known() + validated = true } - fun toBuilder() = Builder().from(this) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 InlineContext && - this.runtime == other.runtime && - this.version == other.version && - this.additionalProperties == other.additionalProperties + return other is ObjectType && value == other.value } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtime, - version, - additionalProperties, - ) - } - return hashCode - } + override fun hashCode() = value.hashCode() - override fun toString() = - "InlineContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + override fun toString() = value.toString() + } + + /** Include these properties in every span created under this parent */ + class PropagatedEvent + @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 [PropagatedEvent]. + */ fun builder() = Builder() } - class Builder { + /** A builder for [PropagatedEvent]. */ + class Builder internal constructor() { - private var runtime: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(inlineContext: InlineContext) = apply { - this.runtime = inlineContext.runtime - this.version = inlineContext.version - additionalProperties(inlineContext.additionalProperties) + internal fun from(propagatedEvent: PropagatedEvent) = apply { + additionalProperties = propagatedEvent.additionalProperties.toMutableMap() } - fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) - - @JsonProperty("runtime") - @ExcludeMissing - fun runtime(runtime: JsonField) = apply { this.runtime = runtime } - - fun version(version: String) = version(JsonField.of(version)) - - @JsonProperty("version") - @ExcludeMissing - fun version(version: JsonField) = apply { this.version = version } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2992,265 +8024,358 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): InlineContext = - InlineContext( - runtime, - version, - additionalProperties.toUnmodifiable(), - ) - } - - class Runtime - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Runtime && this.value == other.value + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) } - override fun hashCode() = value.hashCode() + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - override fun toString() = value.toString() + /** + * Returns an immutable instance of [PropagatedEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PropagatedEvent = + PropagatedEvent(additionalProperties.toImmutable()) + } - companion object { + private var validated: Boolean = false - val NODE = Runtime(JsonField.of("node")) + fun validate(): PropagatedEvent = apply { + if (validated) { + return@apply + } - val PYTHON = Runtime(JsonField.of("python")) + validated = true + } - fun of(value: String) = Runtime(JsonField.of(value)) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - enum class Known { - NODE, - PYTHON, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() } - enum class Value { - NODE, - PYTHON, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - NODE -> Value.NODE - PYTHON -> Value.PYTHON - else -> Value._UNKNOWN - } + return other is PropagatedEvent && + additionalProperties == other.additionalProperties + } - fun known(): Known = - when (this) { - NODE -> Known.NODE - PYTHON -> Known.PYTHON - else -> throw BraintrustInvalidDataException("Unknown Runtime: $value") - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - fun asString(): String = _value().asStringOrThrow() - } + override fun hashCode(): Int = hashCode + + override fun toString() = + "PropagatedEvent{additionalProperties=$additionalProperties}" } - } - /** Inline prompt definition */ - @JsonDeserialize(builder = InlinePrompt.Builder::class) - @NoAutoDetect - class InlinePrompt - private constructor( - private val inlinePrompt: JsonField, - private val name: JsonField, - private val additionalProperties: Map, - ) { + /** Identifiers for the row to to log a subspan under */ + class RowIds + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val rootSpanId: JsonField, + private val spanId: JsonField, + private val additionalProperties: MutableMap, + ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("span_id") + @ExcludeMissing + spanId: JsonField = JsonMissing.of(), + ) : this(id, rootSpanId, spanId, mutableMapOf()) - private var hashCode: Int = 0 + /** + * The id of the row + * + * @throws BraintrustInvalidDataException 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") - /** The prompt, model, and its parameters */ - fun inlinePrompt(): PromptData? = inlinePrompt.getNullable("inline_prompt") + /** + * The root_span_id of the row + * + * @throws BraintrustInvalidDataException 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 rootSpanId(): String = rootSpanId.getRequired("root_span_id") - /** The name of the inline prompt */ - fun name(): String? = name.getNullable("name") + /** + * The span_id of the row + * + * @throws BraintrustInvalidDataException 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 spanId(): String = spanId.getRequired("span_id") - /** The prompt, model, and its parameters */ - @JsonProperty("inline_prompt") @ExcludeMissing fun _inlinePrompt() = inlinePrompt + /** + * 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 - /** The name of the inline prompt */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("root_span_id") + @ExcludeMissing + fun _rootSpanId(): JsonField = rootSpanId - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId - fun validate(): InlinePrompt = apply { - if (!validated) { - inlinePrompt()?.validate() - name() - validated = true + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - } - fun toBuilder() = Builder().from(this) + @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 InlinePrompt && - this.inlinePrompt == other.inlinePrompt && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - inlinePrompt, - name, - additionalProperties, - ) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [RowIds]. + * + * The following fields are required: + * ```kotlin + * .id() + * .rootSpanId() + * .spanId() + * ``` + */ + fun builder() = Builder() } - return hashCode - } - override fun toString() = - "InlinePrompt{inlinePrompt=$inlinePrompt, name=$name, additionalProperties=$additionalProperties}" + /** A builder for [RowIds]. */ + class Builder internal constructor() { - companion object { + private var id: JsonField? = null + private var rootSpanId: JsonField? = null + private var spanId: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun builder() = Builder() - } + internal fun from(rowIds: RowIds) = apply { + id = rowIds.id + rootSpanId = rowIds.rootSpanId + spanId = rowIds.spanId + additionalProperties = rowIds.additionalProperties.toMutableMap() + } - class Builder { + /** The id of the row */ + 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 } + + /** The root_span_id of the row */ + fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) + + /** + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun rootSpanId(rootSpanId: JsonField) = apply { + this.rootSpanId = rootSpanId + } - private var inlinePrompt: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + /** The span_id of the row */ + fun spanId(spanId: String) = spanId(JsonField.of(spanId)) - internal fun from(inlinePrompt: InlinePrompt) = apply { - this.inlinePrompt = inlinePrompt.inlinePrompt - this.name = inlinePrompt.name - additionalProperties(inlinePrompt.additionalProperties) - } + /** + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } - /** The prompt, model, and its parameters */ - fun inlinePrompt(inlinePrompt: PromptData) = - inlinePrompt(JsonField.of(inlinePrompt)) + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - /** The prompt, model, and its parameters */ - @JsonProperty("inline_prompt") - @ExcludeMissing - fun inlinePrompt(inlinePrompt: JsonField) = apply { - this.inlinePrompt = inlinePrompt - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - /** The name of the inline prompt */ - fun name(name: String) = name(JsonField.of(name)) + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } - /** The name of the inline prompt */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + /** + * Returns an immutable instance of [RowIds]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .rootSpanId() + * .spanId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RowIds = + RowIds( + checkRequired("id", id), + checkRequired("rootSpanId", rootSpanId), + checkRequired("spanId", spanId), + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) + private var validated: Boolean = false + + fun validate(): RowIds = apply { + if (validated) { + return@apply } - fun build(): InlinePrompt = - InlinePrompt( - inlinePrompt, - name, - additionalProperties.toUnmodifiable(), - ) - } - } - } + id() + rootSpanId() + spanId() + validated = true + } - /** - * Optional experiment-level metadata to store about the evaluation. You can later use this to - * slice & dice across experiments. - */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - private var hashCode: Int = 0 + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (if (spanId.asKnown() == null) 0 else 1) - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun toBuilder() = Builder().from(this) + return other is RowIds && + id == other.id && + rootSpanId == other.rootSpanId && + spanId == other.spanId && + additionalProperties == other.additionalProperties + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private val hashCode: Int by lazy { + Objects.hash(id, rootSpanId, spanId, additionalProperties) + } - return other is Metadata && this.additionalProperties == other.additionalProperties - } + override fun hashCode(): Int = hashCode - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) + override fun toString() = + "RowIds{id=$id, rootSpanId=$rootSpanId, spanId=$spanId, additionalProperties=$additionalProperties}" } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + return other is SpanParentStruct && + objectId == other.objectId && + objectType == other.objectType && + propagatedEvent == other.propagatedEvent && + rowIds == other.rowIds && + additionalProperties == other.additionalProperties } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + private val hashCode: Int by lazy { + Objects.hash(objectId, objectType, propagatedEvent, rowIds, additionalProperties) } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + override fun hashCode(): Int = hashCode - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun toString() = + "SpanParentStruct{objectId=$objectId, objectType=$objectType, propagatedEvent=$propagatedEvent, rowIds=$rowIds, additionalProperties=$additionalProperties}" + } + } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is EvalCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "EvalCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Experiment.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Experiment.kt index 1ca9c8d8..740fa980 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Experiment.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Experiment.kt @@ -6,484 +6,786 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = Experiment.Builder::class) -@NoAutoDetect class Experiment +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val projectId: JsonField, private val name: JsonField, - private val description: JsonField, - private val created: JsonField, - private val repoInfo: JsonField, - private val commit: JsonField, + private val projectId: JsonField, + private val public_: JsonField, private val baseExpId: JsonField, - private val deletedAt: JsonField, + private val commit: JsonField, + private val created: JsonField, private val datasetId: JsonField, private val datasetVersion: JsonField, - private val public_: JsonField, - private val userId: JsonField, + private val deletedAt: JsonField, + private val description: JsonField, private val metadata: JsonField, - private val additionalProperties: Map, + private val repoInfo: JsonField, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("public") @ExcludeMissing public_: JsonField = JsonMissing.of(), + @JsonProperty("base_exp_id") + @ExcludeMissing + baseExpId: JsonField = JsonMissing.of(), + @JsonProperty("commit") @ExcludeMissing commit: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("dataset_id") @ExcludeMissing datasetId: JsonField = JsonMissing.of(), + @JsonProperty("dataset_version") + @ExcludeMissing + datasetVersion: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("repo_info") @ExcludeMissing repoInfo: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( + id, + name, + projectId, + public_, + baseExpId, + commit, + created, + datasetId, + datasetVersion, + deletedAt, + description, + metadata, + repoInfo, + userId, + mutableMapOf(), + ) - /** Unique identifier for the experiment */ + /** + * Unique identifier for the experiment + * + * @throws BraintrustInvalidDataException 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") - /** Unique identifier for the project that the experiment belongs under */ - fun projectId(): String = projectId.getRequired("project_id") - - /** Name of the experiment. Within a project, experiment names are unique */ + /** + * Name of the experiment. Within a project, experiment names are unique + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** Textual description of the experiment */ - fun description(): String? = description.getNullable("description") + /** + * Unique identifier for the project that the experiment belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** Date of experiment creation */ - fun created(): OffsetDateTime? = created.getNullable("created") + /** + * Whether or not the experiment is public. Public experiments can be viewed by anybody inside + * or outside the organization + * + * @throws BraintrustInvalidDataException 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 public_(): Boolean = public_.getRequired("public") - /** Metadata about the state of the repo when the experiment was created */ - fun repoInfo(): RepoInfo? = repoInfo.getNullable("repo_info") + /** + * Id of default base experiment to compare against when viewing this experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baseExpId(): String? = baseExpId.getNullable("base_exp_id") - /** Commit, taken directly from `repo_info.commit` */ + /** + * Commit, taken directly from `repo_info.commit` + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun commit(): String? = commit.getNullable("commit") - /** Id of default base experiment to compare against when viewing this experiment */ - fun baseExpId(): String? = baseExpId.getNullable("base_exp_id") - - /** Date of experiment deletion, or null if the experiment is still active */ - fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") + /** + * Date of experiment creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") - /** Identifier of the linked dataset, or null if the experiment is not linked to a dataset */ + /** + * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun datasetId(): String? = datasetId.getNullable("dataset_id") /** * Version number of the linked dataset the experiment was run against. This can be used to * reproduce the experiment after the dataset has been modified. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun datasetVersion(): String? = datasetVersion.getNullable("dataset_version") /** - * Whether or not the experiment is public. Public experiments can be viewed by anybody inside - * or outside the organization + * Date of experiment deletion, or null if the experiment is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun public_(): Boolean = public_.getRequired("public") + fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - /** Identifies the user who created the experiment */ - fun userId(): String? = userId.getNullable("user_id") + /** + * Textual description of the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - /** User-controlled metadata about the experiment */ + /** + * User-controlled metadata about the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** Unique identifier for the experiment */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Unique identifier for the project that the experiment belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId - - /** Name of the experiment. Within a project, experiment names are unique */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Textual description of the experiment */ - @JsonProperty("description") @ExcludeMissing fun _description() = description + /** + * Metadata about the state of the repo when the experiment was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun repoInfo(): RepoInfo? = repoInfo.getNullable("repo_info") - /** Date of experiment creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * Identifies the user who created the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - /** Metadata about the state of the repo when the experiment was created */ - @JsonProperty("repo_info") @ExcludeMissing fun _repoInfo() = repoInfo + /** + * 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 - /** Commit, taken directly from `repo_info.commit` */ - @JsonProperty("commit") @ExcludeMissing fun _commit() = commit + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Id of default base experiment to compare against when viewing this experiment */ - @JsonProperty("base_exp_id") @ExcludeMissing fun _baseExpId() = baseExpId + /** + * 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 - /** Date of experiment deletion, or null if the experiment is still active */ - @JsonProperty("deleted_at") @ExcludeMissing fun _deletedAt() = deletedAt + /** + * Returns the raw JSON value of [public_]. + * + * Unlike [public_], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("public") @ExcludeMissing fun _public_(): JsonField = public_ - /** Identifier of the linked dataset, or null if the experiment is not linked to a dataset */ - @JsonProperty("dataset_id") @ExcludeMissing fun _datasetId() = datasetId + /** + * Returns the raw JSON value of [baseExpId]. + * + * Unlike [baseExpId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("base_exp_id") @ExcludeMissing fun _baseExpId(): JsonField = baseExpId /** - * Version number of the linked dataset the experiment was run against. This can be used to - * reproduce the experiment after the dataset has been modified. + * Returns the raw JSON value of [commit]. + * + * Unlike [commit], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("dataset_version") @ExcludeMissing fun _datasetVersion() = datasetVersion + @JsonProperty("commit") @ExcludeMissing fun _commit(): JsonField = commit /** - * Whether or not the experiment is public. Public experiments can be viewed by anybody inside - * or outside the organization + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("public") @ExcludeMissing fun _public_() = public_ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - /** Identifies the user who created the experiment */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + /** + * Returns the raw JSON value of [datasetId]. + * + * Unlike [datasetId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dataset_id") @ExcludeMissing fun _datasetId(): JsonField = datasetId - /** User-controlled metadata about the experiment */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata + /** + * Returns the raw JSON value of [datasetVersion]. + * + * Unlike [datasetVersion], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dataset_version") + @ExcludeMissing + fun _datasetVersion(): JsonField = datasetVersion - @JsonAnyGetter + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _deletedAt(): JsonField = deletedAt - fun validate(): Experiment = apply { - if (!validated) { - id() - projectId() - name() - description() - created() - repoInfo()?.validate() - commit() - baseExpId() - deletedAt() - datasetId() - datasetVersion() - public_() - userId() - metadata()?.validate() - validated = true - } - } + /** + * 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 - fun toBuilder() = Builder().from(this) + /** + * 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 - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [repoInfo]. + * + * Unlike [repoInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("repo_info") @ExcludeMissing fun _repoInfo(): JsonField = repoInfo - return other is Experiment && - this.id == other.id && - this.projectId == other.projectId && - this.name == other.name && - this.description == other.description && - this.created == other.created && - this.repoInfo == other.repoInfo && - this.commit == other.commit && - this.baseExpId == other.baseExpId && - this.deletedAt == other.deletedAt && - this.datasetId == other.datasetId && - this.datasetVersion == other.datasetVersion && - this.public_ == other.public_ && - this.userId == other.userId && - this.metadata == other.metadata && - this.additionalProperties == other.additionalProperties - } + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - projectId, - name, - description, - created, - repoInfo, - commit, - baseExpId, - deletedAt, - datasetId, - datasetVersion, - public_, - userId, - metadata, - additionalProperties, - ) - } - return hashCode + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "Experiment{id=$id, projectId=$projectId, name=$name, description=$description, created=$created, repoInfo=$repoInfo, commit=$commit, baseExpId=$baseExpId, deletedAt=$deletedAt, datasetId=$datasetId, datasetVersion=$datasetVersion, public_=$public_, userId=$userId, metadata=$metadata, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Experiment]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .public_() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Experiment]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var repoInfo: JsonField = JsonMissing.of() - private var commit: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var projectId: JsonField? = null + private var public_: JsonField? = null private var baseExpId: JsonField = JsonMissing.of() - private var deletedAt: JsonField = JsonMissing.of() + private var commit: JsonField = JsonMissing.of() + private var created: JsonField = JsonMissing.of() private var datasetId: JsonField = JsonMissing.of() private var datasetVersion: JsonField = JsonMissing.of() - private var public_: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() + private var deletedAt: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() + private var repoInfo: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(experiment: Experiment) = apply { - this.id = experiment.id - this.projectId = experiment.projectId - this.name = experiment.name - this.description = experiment.description - this.created = experiment.created - this.repoInfo = experiment.repoInfo - this.commit = experiment.commit - this.baseExpId = experiment.baseExpId - this.deletedAt = experiment.deletedAt - this.datasetId = experiment.datasetId - this.datasetVersion = experiment.datasetVersion - this.public_ = experiment.public_ - this.userId = experiment.userId - this.metadata = experiment.metadata - additionalProperties(experiment.additionalProperties) + id = experiment.id + name = experiment.name + projectId = experiment.projectId + public_ = experiment.public_ + baseExpId = experiment.baseExpId + commit = experiment.commit + created = experiment.created + datasetId = experiment.datasetId + datasetVersion = experiment.datasetVersion + deletedAt = experiment.deletedAt + description = experiment.description + metadata = experiment.metadata + repoInfo = experiment.repoInfo + userId = experiment.userId + additionalProperties = experiment.additionalProperties.toMutableMap() } /** Unique identifier for the experiment */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the experiment */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** Unique identifier for the project that the experiment belongs under */ - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - /** Unique identifier for the project that the experiment belongs under */ - @JsonProperty("project_id") - @ExcludeMissing - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } + /** + * 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 } /** Name of the experiment. Within a project, experiment names are unique */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the experiment. Within a project, experiment names are unique */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } - /** Textual description of the experiment */ - fun description(description: String) = description(JsonField.of(description)) + /** Unique identifier for the project that the experiment belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Textual description of the experiment */ - @JsonProperty("description") - @ExcludeMissing - fun description(description: JsonField) = apply { this.description = description } + /** + * 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 } - /** Date of experiment creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** + * Whether or not the experiment is public. Public experiments can be viewed by anybody + * inside or outside the organization + */ + fun public_(public_: Boolean) = public_(JsonField.of(public_)) - /** Date of experiment creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } + /** + * Sets [Builder.public_] to an arbitrary JSON value. + * + * You should usually call [Builder.public_] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun public_(public_: JsonField) = apply { this.public_ = public_ } - /** Metadata about the state of the repo when the experiment was created */ - fun repoInfo(repoInfo: RepoInfo) = repoInfo(JsonField.of(repoInfo)) + /** Id of default base experiment to compare against when viewing this experiment */ + fun baseExpId(baseExpId: String?) = baseExpId(JsonField.ofNullable(baseExpId)) - /** Metadata about the state of the repo when the experiment was created */ - @JsonProperty("repo_info") - @ExcludeMissing - fun repoInfo(repoInfo: JsonField) = apply { this.repoInfo = repoInfo } + /** + * Sets [Builder.baseExpId] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExpId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun baseExpId(baseExpId: JsonField) = apply { this.baseExpId = baseExpId } /** Commit, taken directly from `repo_info.commit` */ - fun commit(commit: String) = commit(JsonField.of(commit)) + fun commit(commit: String?) = commit(JsonField.ofNullable(commit)) - /** Commit, taken directly from `repo_info.commit` */ - @JsonProperty("commit") - @ExcludeMissing + /** + * Sets [Builder.commit] to an arbitrary JSON value. + * + * You should usually call [Builder.commit] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun commit(commit: JsonField) = apply { this.commit = commit } - /** Id of default base experiment to compare against when viewing this experiment */ - fun baseExpId(baseExpId: String) = baseExpId(JsonField.of(baseExpId)) - - /** Id of default base experiment to compare against when viewing this experiment */ - @JsonProperty("base_exp_id") - @ExcludeMissing - fun baseExpId(baseExpId: JsonField) = apply { this.baseExpId = baseExpId } - - /** Date of experiment deletion, or null if the experiment is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = deletedAt(JsonField.of(deletedAt)) + /** Date of experiment creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) - /** Date of experiment deletion, or null if the experiment is still active */ - @JsonProperty("deleted_at") - @ExcludeMissing - fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } /** * Identifier of the linked dataset, or null if the experiment is not linked to a dataset */ - fun datasetId(datasetId: String) = datasetId(JsonField.of(datasetId)) + fun datasetId(datasetId: String?) = datasetId(JsonField.ofNullable(datasetId)) /** - * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + * Sets [Builder.datasetId] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - @JsonProperty("dataset_id") - @ExcludeMissing fun datasetId(datasetId: JsonField) = apply { this.datasetId = datasetId } /** * Version number of the linked dataset the experiment was run against. This can be used to * reproduce the experiment after the dataset has been modified. */ - fun datasetVersion(datasetVersion: String) = datasetVersion(JsonField.of(datasetVersion)) + fun datasetVersion(datasetVersion: String?) = + datasetVersion(JsonField.ofNullable(datasetVersion)) /** - * Version number of the linked dataset the experiment was run against. This can be used to - * reproduce the experiment after the dataset has been modified. + * Sets [Builder.datasetVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetVersion] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("dataset_version") - @ExcludeMissing fun datasetVersion(datasetVersion: JsonField) = apply { this.datasetVersion = datasetVersion } - /** - * Whether or not the experiment is public. Public experiments can be viewed by anybody - * inside or outside the organization - */ - fun public_(public_: Boolean) = public_(JsonField.of(public_)) + /** Date of experiment deletion, or null if the experiment is still active */ + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) /** - * Whether or not the experiment is public. Public experiments can be viewed by anybody - * inside or outside the organization + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("public") - @ExcludeMissing - fun public_(public_: JsonField) = apply { this.public_ = public_ } + fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } - /** Identifies the user who created the experiment */ - fun userId(userId: String) = userId(JsonField.of(userId)) + /** Textual description of the experiment */ + fun description(description: String?) = description(JsonField.ofNullable(description)) - /** Identifies the user who created the experiment */ - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } + /** + * 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 } /** User-controlled metadata about the experiment */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) - /** User-controlled metadata about the experiment */ - @JsonProperty("metadata") - @ExcludeMissing + /** + * 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 } + /** Metadata about the state of the repo when the experiment was created */ + fun repoInfo(repoInfo: RepoInfo?) = repoInfo(JsonField.ofNullable(repoInfo)) + + /** + * Sets [Builder.repoInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.repoInfo] with a well-typed [RepoInfo] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun repoInfo(repoInfo: JsonField) = apply { this.repoInfo = repoInfo } + + /** Identifies the user who created the experiment */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Experiment]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .public_() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Experiment = Experiment( - id, - projectId, - name, - description, - created, - repoInfo, - commit, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("public_", public_), baseExpId, - deletedAt, + commit, + created, datasetId, datasetVersion, - public_, - userId, + deletedAt, + description, metadata, - additionalProperties.toUnmodifiable(), + repoInfo, + userId, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Experiment = apply { + if (validated) { + return@apply + } + + id() + name() + projectId() + public_() + baseExpId() + commit() + created() + datasetId() + datasetVersion() + deletedAt() + description() + metadata()?.validate() + repoInfo()?.validate() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (public_.asKnown() == null) 0 else 1) + + (if (baseExpId.asKnown() == null) 0 else 1) + + (if (commit.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (datasetId.asKnown() == null) 0 else 1) + + (if (datasetVersion.asKnown() == null) 0 else 1) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (repoInfo.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + /** User-controlled metadata about the experiment */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Experiment && + id == other.id && + name == other.name && + projectId == other.projectId && + public_ == other.public_ && + baseExpId == other.baseExpId && + commit == other.commit && + created == other.created && + datasetId == other.datasetId && + datasetVersion == other.datasetVersion && + deletedAt == other.deletedAt && + description == other.description && + metadata == other.metadata && + repoInfo == other.repoInfo && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + projectId, + public_, + baseExpId, + commit, + created, + datasetId, + datasetVersion, + deletedAt, + description, + metadata, + repoInfo, + userId, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Experiment{id=$id, name=$name, projectId=$projectId, public_=$public_, baseExpId=$baseExpId, commit=$commit, created=$created, datasetId=$datasetId, datasetVersion=$datasetVersion, deletedAt=$deletedAt, description=$description, metadata=$metadata, repoInfo=$repoInfo, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentCreateParams.kt index e43409be..42a23b01 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentCreateParams.kt @@ -3,55 +3,571 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new experiment. If there is an existing experiment in the project with the same name as + * the one specified in the request, will return the existing experiment unmodified + */ class ExperimentCreateParams -constructor( - private val projectId: String, - private val baseExpId: String?, - private val datasetId: String?, - private val datasetVersion: String?, - private val description: String?, - private val ensureNew: Boolean?, - private val metadata: Metadata?, - private val name: String?, - private val public_: Boolean?, - private val repoInfo: RepoInfo?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Unique identifier for the project that the experiment belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Id of default base experiment to compare against when viewing this experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baseExpId(): String? = body.baseExpId() + + /** + * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun datasetId(): String? = body.datasetId() + + /** + * Version number of the linked dataset the experiment was run against. This can be used to + * reproduce the experiment after the dataset has been modified. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun datasetVersion(): String? = body.datasetVersion() + + /** + * Textual description of the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Normally, creating an experiment with the same name as an existing experiment will return the + * existing one un-modified. But if `ensure_new` is true, registration will generate a new + * experiment with a unique name in case of a conflict. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun ensureNew(): Boolean? = body.ensureNew() + + /** + * User-controlled metadata about the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * Name of the experiment. Within a project, experiment names are unique + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * Whether or not the experiment is public. Public experiments can be viewed by anybody inside + * or outside the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun public_(): Boolean? = body.public_() + + /** + * Metadata about the state of the repo when the experiment was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun repoInfo(): RepoInfo? = body.repoInfo() + + /** + * 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 [baseExpId]. + * + * Unlike [baseExpId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _baseExpId(): JsonField = body._baseExpId() + + /** + * Returns the raw JSON value of [datasetId]. + * + * Unlike [datasetId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _datasetId(): JsonField = body._datasetId() + + /** + * Returns the raw JSON value of [datasetVersion]. + * + * Unlike [datasetVersion], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _datasetVersion(): JsonField = body._datasetVersion() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [ensureNew]. + * + * Unlike [ensureNew], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _ensureNew(): JsonField = body._ensureNew() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [public_]. + * + * Unlike [public_], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _public_(): JsonField = body._public_() + + /** + * Returns the raw JSON value of [repoInfo]. + * + * Unlike [repoInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _repoInfo(): JsonField = body._repoInfo() + + 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 projectId(): String = projectId + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ExperimentCreateParams]. + * + * The following fields are required: + * ```kotlin + * .projectId() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ExperimentCreateParams]. */ + class Builder internal constructor() { - fun baseExpId(): String? = baseExpId + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun datasetId(): String? = datasetId + internal fun from(experimentCreateParams: ExperimentCreateParams) = apply { + body = experimentCreateParams.body.toBuilder() + additionalHeaders = experimentCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentCreateParams.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: + * - [projectId] + * - [baseExpId] + * - [datasetId] + * - [datasetVersion] + * - [description] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } - fun datasetVersion(): String? = datasetVersion + /** Unique identifier for the project that the experiment belongs under */ + fun projectId(projectId: String) = apply { body.projectId(projectId) } - fun description(): String? = description + /** + * 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) } - fun ensureNew(): Boolean? = ensureNew + /** Id of default base experiment to compare against when viewing this experiment */ + fun baseExpId(baseExpId: String?) = apply { body.baseExpId(baseExpId) } - fun metadata(): Metadata? = metadata + /** + * Sets [Builder.baseExpId] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExpId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun baseExpId(baseExpId: JsonField) = apply { body.baseExpId(baseExpId) } - fun name(): String? = name + /** + * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + */ + fun datasetId(datasetId: String?) = apply { body.datasetId(datasetId) } - fun public_(): Boolean? = public_ + /** + * Sets [Builder.datasetId] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun datasetId(datasetId: JsonField) = apply { body.datasetId(datasetId) } - fun repoInfo(): RepoInfo? = repoInfo + /** + * Version number of the linked dataset the experiment was run against. This can be used to + * reproduce the experiment after the dataset has been modified. + */ + fun datasetVersion(datasetVersion: String?) = apply { body.datasetVersion(datasetVersion) } + + /** + * Sets [Builder.datasetVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetVersion] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun datasetVersion(datasetVersion: JsonField) = apply { + body.datasetVersion(datasetVersion) + } + + /** Textual description of the experiment */ + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + /** + * Normally, creating an experiment with the same name as an existing experiment will return + * the existing one un-modified. But if `ensure_new` is true, registration will generate a + * new experiment with a unique name in case of a conflict. + */ + fun ensureNew(ensureNew: Boolean?) = apply { body.ensureNew(ensureNew) } + + /** + * Alias for [Builder.ensureNew]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun ensureNew(ensureNew: Boolean) = ensureNew(ensureNew as Boolean?) + + /** + * Sets [Builder.ensureNew] to an arbitrary JSON value. + * + * You should usually call [Builder.ensureNew] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun ensureNew(ensureNew: JsonField) = apply { body.ensureNew(ensureNew) } + + /** User-controlled metadata about the experiment */ + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } - internal fun getBody(): ExperimentCreateBody { - return ExperimentCreateBody( + /** Name of the experiment. Within a project, experiment names are unique */ + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + /** + * Whether or not the experiment is public. Public experiments can be viewed by anybody + * inside or outside the organization + */ + fun public_(public_: Boolean?) = apply { body.public_(public_) } + + /** + * Alias for [Builder.public_]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun public_(public_: Boolean) = public_(public_ as Boolean?) + + /** + * Sets [Builder.public_] to an arbitrary JSON value. + * + * You should usually call [Builder.public_] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun public_(public_: JsonField) = apply { body.public_(public_) } + + /** Metadata about the state of the repo when the experiment was created */ + fun repoInfo(repoInfo: RepoInfo?) = apply { body.repoInfo(repoInfo) } + + /** + * Sets [Builder.repoInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.repoInfo] with a well-typed [RepoInfo] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun repoInfo(repoInfo: JsonField) = apply { body.repoInfo(repoInfo) } + + 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 [ExperimentCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExperimentCreateParams = + ExperimentCreateParams( + 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 projectId: JsonField, + private val baseExpId: JsonField, + private val datasetId: JsonField, + private val datasetVersion: JsonField, + private val description: JsonField, + private val ensureNew: JsonField, + private val metadata: JsonField, + private val name: JsonField, + private val public_: JsonField, + private val repoInfo: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("base_exp_id") + @ExcludeMissing + baseExpId: JsonField = JsonMissing.of(), + @JsonProperty("dataset_id") + @ExcludeMissing + datasetId: JsonField = JsonMissing.of(), + @JsonProperty("dataset_version") + @ExcludeMissing + datasetVersion: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("ensure_new") + @ExcludeMissing + ensureNew: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("public") @ExcludeMissing public_: JsonField = JsonMissing.of(), + @JsonProperty("repo_info") + @ExcludeMissing + repoInfo: JsonField = JsonMissing.of(), + ) : this( projectId, baseExpId, datasetId, @@ -62,226 +578,408 @@ constructor( name, public_, repoInfo, - additionalBodyProperties, + mutableMapOf(), ) - } - - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = ExperimentCreateBody.Builder::class) - @NoAutoDetect - class ExperimentCreateBody - internal constructor( - private val projectId: String?, - private val baseExpId: String?, - private val datasetId: String?, - private val datasetVersion: String?, - private val description: String?, - private val ensureNew: Boolean?, - private val metadata: Metadata?, - private val name: String?, - private val public_: Boolean?, - private val repoInfo: RepoInfo?, - private val additionalProperties: Map, - ) { - - private var hashCode: Int = 0 - /** Unique identifier for the project that the experiment belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + /** + * Unique identifier for the project that the experiment belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** Id of default base experiment to compare against when viewing this experiment */ - @JsonProperty("base_exp_id") fun baseExpId(): String? = baseExpId + /** + * Id of default base experiment to compare against when viewing this experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun baseExpId(): String? = baseExpId.getNullable("base_exp_id") /** * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("dataset_id") fun datasetId(): String? = datasetId + fun datasetId(): String? = datasetId.getNullable("dataset_id") /** * Version number of the linked dataset the experiment was run against. This can be used to * reproduce the experiment after the dataset has been modified. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("dataset_version") fun datasetVersion(): String? = datasetVersion + fun datasetVersion(): String? = datasetVersion.getNullable("dataset_version") - /** Textual description of the experiment */ - @JsonProperty("description") fun description(): String? = description + /** + * Textual description of the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") /** * Normally, creating an experiment with the same name as an existing experiment will return * the existing one un-modified. But if `ensure_new` is true, registration will generate a * new experiment with a unique name in case of a conflict. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("ensure_new") fun ensureNew(): Boolean? = ensureNew + fun ensureNew(): Boolean? = ensureNew.getNullable("ensure_new") - /** User-controlled metadata about the experiment */ - @JsonProperty("metadata") fun metadata(): Metadata? = metadata + /** + * User-controlled metadata about the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") - /** Name of the experiment. Within a project, experiment names are unique */ - @JsonProperty("name") fun name(): String? = name + /** + * Name of the experiment. Within a project, experiment names are unique + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") /** * Whether or not the experiment is public. Public experiments can be viewed by anybody * inside or outside the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("public") fun public_(): Boolean? = public_ + fun public_(): Boolean? = public_.getNullable("public") - /** Metadata about the state of the repo when the experiment was created */ - @JsonProperty("repo_info") fun repoInfo(): RepoInfo? = repoInfo + /** + * Metadata about the state of the repo when the experiment was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun repoInfo(): RepoInfo? = repoInfo.getNullable("repo_info") - @JsonAnyGetter + /** + * 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 [baseExpId]. + * + * Unlike [baseExpId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("base_exp_id") @ExcludeMissing fun _baseExpId(): JsonField = baseExpId + + /** + * Returns the raw JSON value of [datasetId]. + * + * Unlike [datasetId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dataset_id") @ExcludeMissing fun _datasetId(): JsonField = datasetId + + /** + * Returns the raw JSON value of [datasetVersion]. + * + * Unlike [datasetVersion], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("dataset_version") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _datasetVersion(): JsonField = datasetVersion - fun toBuilder() = Builder().from(this) + /** + * 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 - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [ensureNew]. + * + * Unlike [ensureNew], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("ensure_new") @ExcludeMissing fun _ensureNew(): JsonField = ensureNew - return other is ExperimentCreateBody && - this.projectId == other.projectId && - this.baseExpId == other.baseExpId && - this.datasetId == other.datasetId && - this.datasetVersion == other.datasetVersion && - this.description == other.description && - this.ensureNew == other.ensureNew && - this.metadata == other.metadata && - this.name == other.name && - this.public_ == other.public_ && - this.repoInfo == other.repoInfo && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - projectId, - baseExpId, - datasetId, - datasetVersion, - description, - ensureNew, - metadata, - name, - public_, - repoInfo, - additionalProperties, - ) - } - return hashCode + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [public_]. + * + * Unlike [public_], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("public") @ExcludeMissing fun _public_(): JsonField = public_ + + /** + * Returns the raw JSON value of [repoInfo]. + * + * Unlike [repoInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("repo_info") @ExcludeMissing fun _repoInfo(): JsonField = repoInfo + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "ExperimentCreateBody{projectId=$projectId, baseExpId=$baseExpId, datasetId=$datasetId, datasetVersion=$datasetVersion, description=$description, ensureNew=$ensureNew, metadata=$metadata, name=$name, public_=$public_, repoInfo=$repoInfo, additionalProperties=$additionalProperties}" + @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: + * ```kotlin + * .projectId() + * ``` + */ fun builder() = Builder() } - class Builder { - - private var projectId: String? = null - private var baseExpId: String? = null - private var datasetId: String? = null - private var datasetVersion: String? = null - private var description: String? = null - private var ensureNew: Boolean? = null - private var metadata: Metadata? = null - private var name: String? = null - private var public_: Boolean? = null - private var repoInfo: RepoInfo? = null + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var projectId: JsonField? = null + private var baseExpId: JsonField = JsonMissing.of() + private var datasetId: JsonField = JsonMissing.of() + private var datasetVersion: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var ensureNew: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var public_: JsonField = JsonMissing.of() + private var repoInfo: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(experimentCreateBody: ExperimentCreateBody) = apply { - this.projectId = experimentCreateBody.projectId - this.baseExpId = experimentCreateBody.baseExpId - this.datasetId = experimentCreateBody.datasetId - this.datasetVersion = experimentCreateBody.datasetVersion - this.description = experimentCreateBody.description - this.ensureNew = experimentCreateBody.ensureNew - this.metadata = experimentCreateBody.metadata - this.name = experimentCreateBody.name - this.public_ = experimentCreateBody.public_ - this.repoInfo = experimentCreateBody.repoInfo - additionalProperties(experimentCreateBody.additionalProperties) + internal fun from(body: Body) = apply { + projectId = body.projectId + baseExpId = body.baseExpId + datasetId = body.datasetId + datasetVersion = body.datasetVersion + description = body.description + ensureNew = body.ensureNew + metadata = body.metadata + name = body.name + public_ = body.public_ + repoInfo = body.repoInfo + additionalProperties = body.additionalProperties.toMutableMap() } /** Unique identifier for the project that the experiment belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + 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 } /** Id of default base experiment to compare against when viewing this experiment */ - @JsonProperty("base_exp_id") - fun baseExpId(baseExpId: String) = apply { this.baseExpId = baseExpId } + fun baseExpId(baseExpId: String?) = baseExpId(JsonField.ofNullable(baseExpId)) + + /** + * Sets [Builder.baseExpId] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExpId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun baseExpId(baseExpId: JsonField) = apply { this.baseExpId = baseExpId } /** * Identifier of the linked dataset, or null if the experiment is not linked to a * dataset */ - @JsonProperty("dataset_id") - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + fun datasetId(datasetId: String?) = datasetId(JsonField.ofNullable(datasetId)) + + /** + * Sets [Builder.datasetId] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun datasetId(datasetId: JsonField) = apply { this.datasetId = datasetId } /** * Version number of the linked dataset the experiment was run against. This can be used * to reproduce the experiment after the dataset has been modified. */ - @JsonProperty("dataset_version") - fun datasetVersion(datasetVersion: String) = apply { + fun datasetVersion(datasetVersion: String?) = + datasetVersion(JsonField.ofNullable(datasetVersion)) + + /** + * Sets [Builder.datasetVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetVersion] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun datasetVersion(datasetVersion: JsonField) = apply { this.datasetVersion = datasetVersion } /** Textual description of the experiment */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun description(description: String?) = description(JsonField.ofNullable(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 + } /** * Normally, creating an experiment with the same name as an existing experiment will * return the existing one un-modified. But if `ensure_new` is true, registration will * generate a new experiment with a unique name in case of a conflict. */ - @JsonProperty("ensure_new") - fun ensureNew(ensureNew: Boolean) = apply { this.ensureNew = ensureNew } + fun ensureNew(ensureNew: Boolean?) = ensureNew(JsonField.ofNullable(ensureNew)) + + /** + * Alias for [Builder.ensureNew]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun ensureNew(ensureNew: Boolean) = ensureNew(ensureNew as Boolean?) + + /** + * Sets [Builder.ensureNew] to an arbitrary JSON value. + * + * You should usually call [Builder.ensureNew] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun ensureNew(ensureNew: JsonField) = apply { this.ensureNew = ensureNew } /** User-controlled metadata about the experiment */ - @JsonProperty("metadata") - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } /** Name of the experiment. Within a project, experiment names are unique */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } /** * Whether or not the experiment is public. Public experiments can be viewed by anybody * inside or outside the organization */ - @JsonProperty("public") fun public_(public_: Boolean) = apply { this.public_ = public_ } + fun public_(public_: Boolean?) = public_(JsonField.ofNullable(public_)) + + /** + * Alias for [Builder.public_]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun public_(public_: Boolean) = public_(public_ as Boolean?) + + /** + * Sets [Builder.public_] to an arbitrary JSON value. + * + * You should usually call [Builder.public_] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun public_(public_: JsonField) = apply { this.public_ = public_ } /** Metadata about the state of the repo when the experiment was created */ - @JsonProperty("repo_info") - fun repoInfo(repoInfo: RepoInfo) = apply { this.repoInfo = repoInfo } + fun repoInfo(repoInfo: RepoInfo?) = repoInfo(JsonField.ofNullable(repoInfo)) + + /** + * Sets [Builder.repoInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.repoInfo] with a well-typed [RepoInfo] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun repoInfo(repoInfo: JsonField) = apply { this.repoInfo = repoInfo } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): ExperimentCreateBody = - ExperimentCreateBody( - checkNotNull(projectId) { "`projectId` is required but was not set" }, + 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: + * ```kotlin + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("projectId", projectId), baseExpId, datasetId, datasetVersion, @@ -291,198 +989,78 @@ constructor( name, public_, repoInfo, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExperimentCreateParams && - this.projectId == other.projectId && - this.baseExpId == other.baseExpId && - this.datasetId == other.datasetId && - this.datasetVersion == other.datasetVersion && - this.description == other.description && - this.ensureNew == other.ensureNew && - this.metadata == other.metadata && - this.name == other.name && - this.public_ == other.public_ && - this.repoInfo == other.repoInfo && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int { - return Objects.hash( - projectId, - baseExpId, - datasetId, - datasetVersion, - description, - ensureNew, - metadata, - name, - public_, - repoInfo, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } - - override fun toString() = - "ExperimentCreateParams{projectId=$projectId, baseExpId=$baseExpId, datasetId=$datasetId, datasetVersion=$datasetVersion, description=$description, ensureNew=$ensureNew, metadata=$metadata, name=$name, public_=$public_, repoInfo=$repoInfo, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) - companion object { - - fun builder() = Builder() - } + private var validated: Boolean = false - @NoAutoDetect - class Builder { - - private var projectId: String? = null - private var baseExpId: String? = null - private var datasetId: String? = null - private var datasetVersion: String? = null - private var description: String? = null - private var ensureNew: Boolean? = null - private var metadata: Metadata? = null - private var name: String? = null - private var public_: Boolean? = null - private var repoInfo: RepoInfo? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun validate(): Body = apply { + if (validated) { + return@apply + } - internal fun from(experimentCreateParams: ExperimentCreateParams) = apply { - this.projectId = experimentCreateParams.projectId - this.baseExpId = experimentCreateParams.baseExpId - this.datasetId = experimentCreateParams.datasetId - this.datasetVersion = experimentCreateParams.datasetVersion - this.description = experimentCreateParams.description - this.ensureNew = experimentCreateParams.ensureNew - this.metadata = experimentCreateParams.metadata - this.name = experimentCreateParams.name - this.public_ = experimentCreateParams.public_ - this.repoInfo = experimentCreateParams.repoInfo - additionalQueryParams(experimentCreateParams.additionalQueryParams) - additionalHeaders(experimentCreateParams.additionalHeaders) - additionalBodyProperties(experimentCreateParams.additionalBodyProperties) + projectId() + baseExpId() + datasetId() + datasetVersion() + description() + ensureNew() + metadata()?.validate() + name() + public_() + repoInfo()?.validate() + validated = true } - /** Unique identifier for the project that the experiment belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } - - /** Id of default base experiment to compare against when viewing this experiment */ - fun baseExpId(baseExpId: String) = apply { this.baseExpId = baseExpId } - - /** - * Identifier of the linked dataset, or null if the experiment is not linked to a dataset - */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } - - /** - * Version number of the linked dataset the experiment was run against. This can be used to - * reproduce the experiment after the dataset has been modified. - */ - fun datasetVersion(datasetVersion: String) = apply { this.datasetVersion = datasetVersion } - - /** Textual description of the experiment */ - fun description(description: String) = apply { this.description = description } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } /** - * Normally, creating an experiment with the same name as an existing experiment will return - * the existing one un-modified. But if `ensure_new` is true, registration will generate a - * new experiment with a unique name in case of a conflict. + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. */ - fun ensureNew(ensureNew: Boolean) = apply { this.ensureNew = ensureNew } - - /** User-controlled metadata about the experiment */ - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } - - /** Name of the experiment. Within a project, experiment names are unique */ - fun name(name: String) = apply { this.name = name } - - /** - * Whether or not the experiment is public. Public experiments can be viewed by anybody - * inside or outside the organization - */ - fun public_(public_: Boolean) = apply { this.public_ = public_ } - - /** Metadata about the state of the repo when the experiment was created */ - fun repoInfo(repoInfo: RepoInfo) = apply { this.repoInfo = repoInfo } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } - - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } - - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } - - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + internal fun validity(): Int = + (if (projectId.asKnown() == null) 0 else 1) + + (if (baseExpId.asKnown() == null) 0 else 1) + + (if (datasetId.asKnown() == null) 0 else 1) + + (if (datasetVersion.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (if (ensureNew.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (if (public_.asKnown() == null) 0 else 1) + + (repoInfo.asKnown()?.validity() ?: 0) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } - - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } - - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } - - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } - - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + return other is Body && + projectId == other.projectId && + baseExpId == other.baseExpId && + datasetId == other.datasetId && + datasetVersion == other.datasetVersion && + description == other.description && + ensureNew == other.ensureNew && + metadata == other.metadata && + name == other.name && + public_ == other.public_ && + repoInfo == other.repoInfo && + additionalProperties == other.additionalProperties } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - - fun build(): ExperimentCreateParams = - ExperimentCreateParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, + private val hashCode: Int by lazy { + Objects.hash( + projectId, baseExpId, datasetId, datasetVersion, @@ -492,73 +1070,127 @@ constructor( name, public_, repoInfo, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{projectId=$projectId, baseExpId=$baseExpId, datasetId=$datasetId, datasetVersion=$datasetVersion, description=$description, ensureNew=$ensureNew, metadata=$metadata, name=$name, public_=$public_, repoInfo=$repoInfo, additionalProperties=$additionalProperties}" } /** User-controlled metadata about the experiment */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExperimentCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ExperimentCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentDeleteParams.kt index f406c710..083e34da 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentDeleteParams.kt @@ -3,138 +3,167 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete an experiment object by its id */ class ExperimentDeleteParams -constructor( - private val experimentId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val experimentId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun experimentId(): String = experimentId + /** Experiment id */ + fun experimentId(): String? = experimentId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ExperimentDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ExperimentDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ExperimentDeleteParams]. */ + class Builder internal constructor() { + + private var experimentId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalHeaders(): Map> = additionalHeaders + internal fun from(experimentDeleteParams: ExperimentDeleteParams) = apply { + experimentId = experimentDeleteParams.experimentId + additionalHeaders = experimentDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + experimentDeleteParams.additionalBodyProperties.toMutableMap() + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + /** Experiment id */ + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ExperimentDeleteParams && - this.experimentId == other.experimentId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - experimentId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "ExperimentDeleteParams{experimentId=$experimentId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var experimentId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(experimentDeleteParams: ExperimentDeleteParams) = apply { - this.experimentId = experimentDeleteParams.experimentId - additionalQueryParams(experimentDeleteParams.additionalQueryParams) - additionalHeaders(experimentDeleteParams.additionalHeaders) - additionalBodyProperties(experimentDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +171,60 @@ constructor( 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 [ExperimentDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ExperimentDeleteParams = ExperimentDeleteParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + experimentId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + 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 ExperimentDeleteParams && + experimentId == other.experimentId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash( + experimentId, + additionalHeaders, + additionalQueryParams, + additionalBodyProperties, + ) + + override fun toString() = + "ExperimentDeleteParams{experimentId=$experimentId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentEvent.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentEvent.kt index 797e1b33..18a8efb6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentEvent.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentEvent.kt @@ -2,96 +2,179 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ExperimentEvent.Builder::class) -@NoAutoDetect class ExperimentEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val datasetRecordId: JsonField, private val _xactId: JsonField, private val created: JsonField, - private val projectId: JsonField, private val experimentId: JsonField, - private val input: JsonValue, - private val output: JsonValue, - private val expected: JsonValue, + private val projectId: JsonField, + private val rootSpanId: JsonField, + private val spanId: JsonField, + private val context: JsonField, private val error: JsonValue, - private val scores: JsonField, + private val expected: JsonValue, + private val input: JsonValue, + private val isRoot: JsonField, private val metadata: JsonField, - private val tags: JsonField>, private val metrics: JsonField, - private val context: JsonField, - private val spanId: JsonField, - private val spanParents: JsonField>, - private val rootSpanId: JsonField, + private val origin: JsonField, + private val output: JsonValue, + private val scores: JsonField, private val spanAttributes: JsonField, - private val additionalProperties: Map, + private val spanParents: JsonField>, + private val tags: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_xact_id") @ExcludeMissing _xactId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("experiment_id") + @ExcludeMissing + experimentId: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("span_id") @ExcludeMissing spanId: JsonField = JsonMissing.of(), + @JsonProperty("context") @ExcludeMissing context: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonValue = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonValue = JsonMissing.of(), + @JsonProperty("is_root") @ExcludeMissing isRoot: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("metrics") @ExcludeMissing metrics: JsonField = JsonMissing.of(), + @JsonProperty("origin") + @ExcludeMissing + origin: JsonField = JsonMissing.of(), + @JsonProperty("output") @ExcludeMissing output: JsonValue = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + @JsonProperty("span_attributes") + @ExcludeMissing + spanAttributes: JsonField = JsonMissing.of(), + @JsonProperty("span_parents") + @ExcludeMissing + spanParents: JsonField> = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _xactId, + created, + experimentId, + projectId, + rootSpanId, + spanId, + context, + error, + expected, + input, + isRoot, + metadata, + metrics, + origin, + output, + scores, + spanAttributes, + spanParents, + tags, + mutableMapOf(), + ) /** * A unique identifier for the experiment event. If you don't provide one, BrainTrust will * generate one for you + * + * @throws BraintrustInvalidDataException 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") - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - fun datasetRecordId(): String? = datasetRecordId.getNullable("dataset_record_id") - /** * The transaction id of an event is unique to the network operation that processed the event * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve * a versioned snapshot of the experiment (see the `version` parameter) + * + * @throws BraintrustInvalidDataException 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 _xactId(): String = _xactId.getRequired("_xact_id") - /** The timestamp the experiment event was created */ + /** + * The timestamp the experiment event was created + * + * @throws BraintrustInvalidDataException 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 created(): OffsetDateTime = created.getRequired("created") - /** Unique identifier for the project that the experiment belongs under */ + /** + * Unique identifier for the experiment + * + * @throws BraintrustInvalidDataException 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 experimentId(): String = experimentId.getRequired("experiment_id") + + /** + * Unique identifier for the project that the experiment belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** Unique identifier for the experiment */ - fun experimentId(): String = experimentId.getRequired("experiment_id") + /** + * A unique identifier for the trace this experiment event belongs to + * + * @throws BraintrustInvalidDataException 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 rootSpanId(): String = rootSpanId.getRequired("root_span_id") /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same between - * experiments, so they should not contain experiment-specific state. A simple rule of thumb is - * that if you run the same experiment twice, the `input` should be identical + * A unique identifier used to link different experiment events together as part of a full + * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full + * details on tracing + * + * @throws BraintrustInvalidDataException 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(): JsonValue = input + fun spanId(): String = spanId.getRequired("span_id") /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question + * Context is additional information about the code that produced the experiment event. It is + * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the + * location in code which produced the experiment event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun output(): JsonValue = output + fun context(): Context? = context.getNullable("context") + + /** The error that occurred, if any. */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonValue = error /** * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to @@ -101,21 +184,23 @@ private constructor( * digging into analyses. However, we may later use these values to re-score outputs or * fine-tune your models */ - fun expected(): JsonValue = expected + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected - /** The error that occurred, if any. */ - fun error(): JsonValue = error + /** + * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). + * Later on, Braintrust will use the `input` to know whether two test cases are the same between + * experiments, so they should not contain experiment-specific state. A simple rule of thumb is + * that if you run the same experiment twice, the `input` should be identical + */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonValue = input /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments + * Whether this span is a root span + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun scores(): Scores? = scores.getNullable("scores") + fun isRoot(): Boolean? = isRoot.getNullable("is_root") /** * A dictionary with additional data about the test example, model outputs, or just about @@ -123,299 +208,274 @@ private constructor( * example, you could log the `prompt`, example's `id`, or anything else that would be useful to * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys * must be strings + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - /** * Metrics are numerical measurements tracking the execution of the code that produced the * experiment event. Use "start" and "end" to track the time span over which the experiment * event was produced + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metrics(): Metrics? = metrics.getNullable("metrics") /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event + * Indicates the event was copied from another object. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun context(): Context? = context.getNullable("context") + fun origin(): ObjectReference? = origin.getNullable("origin") /** - * A unique identifier used to link different experiment events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * The output of your application, including post-processing (an arbitrary, JSON serializable + * object), that allows you to determine whether the result is correct or not. For example, in + * an app that generates SQL queries, the `output` should be the _result_ of the SQL query + * generated by the model, not the query itself, because there may be multiple valid queries + * that answer a single question */ - fun spanId(): String = spanId.getRequired("span_id") + @JsonProperty("output") @ExcludeMissing fun _output(): JsonValue = output /** - * An array of the parent `span_ids` of this experiment event. This should be empty for the root - * span of a trace, and should most often contain just one parent element for subspans + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare experiments + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun spanParents(): List? = spanParents.getNullable("span_parents") - - /** The `span_id` of the root of the trace this experiment event belongs to */ - fun rootSpanId(): String = rootSpanId.getRequired("root_span_id") + fun scores(): Scores? = scores.getNullable("scores") - /** Human-identifying attributes of the span, such as name, type, etc. */ + /** + * Human-identifying attributes of the span, such as name, type, etc. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you + * An array of the parent `span_ids` of this experiment event. This should be empty for the root + * span of a trace, and should most often contain just one parent element for subspans + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("id") @ExcludeMissing fun _id() = id + fun spanParents(): List? = spanParents.getNullable("span_parents") /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("dataset_record_id") @ExcludeMissing fun _datasetRecordId() = datasetRecordId + fun tags(): List? = tags.getNullable("tags") /** - * The transaction id of an event is unique to the network operation that processed the event - * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve - * a versioned snapshot of the experiment (see the `version` parameter) + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("_xact_id") @ExcludeMissing fun __xactId() = _xactId + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id - /** The timestamp the experiment event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * Returns the raw JSON value of [_xactId]. + * + * Unlike [_xactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_xact_id") @ExcludeMissing fun __xactId(): JsonField = _xactId - /** Unique identifier for the project that the experiment belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - /** Unique identifier for the experiment */ - @JsonProperty("experiment_id") @ExcludeMissing fun _experimentId() = experimentId + /** + * Returns the raw JSON value of [experimentId]. + * + * Unlike [experimentId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("experiment_id") + @ExcludeMissing + fun _experimentId(): JsonField = experimentId /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same between - * experiments, so they should not contain experiment-specific state. A simple rule of thumb is - * that if you run the same experiment twice, the `input` should be identical + * Returns the raw JSON value of [projectId]. + * + * Unlike [projectId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("input") @ExcludeMissing fun _input() = input + @JsonProperty("project_id") @ExcludeMissing fun _projectId(): JsonField = projectId /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question + * Returns the raw JSON value of [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("output") @ExcludeMissing fun _output() = output + @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId(): JsonField = rootSpanId /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate your experiments while - * digging into analyses. However, we may later use these values to re-score outputs or - * fine-tune your models + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId - /** The error that occurred, if any. */ - @JsonProperty("error") @ExcludeMissing fun _error() = error + /** + * 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 /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments + * Returns the raw JSON value of [isRoot]. + * + * Unlike [isRoot], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores + @JsonProperty("is_root") @ExcludeMissing fun _isRoot(): JsonField = isRoot /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings + * 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() = metadata + @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags + /** + * Returns the raw JSON value of [metrics]. + * + * Unlike [metrics], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metrics") @ExcludeMissing fun _metrics(): JsonField = metrics /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("metrics") @ExcludeMissing fun _metrics() = metrics + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("context") @ExcludeMissing fun _context() = context + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores /** - * A unique identifier used to link different experiment events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * Returns the raw JSON value of [spanAttributes]. + * + * Unlike [spanAttributes], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("span_id") @ExcludeMissing fun _spanId() = spanId + @JsonProperty("span_attributes") + @ExcludeMissing + fun _spanAttributes(): JsonField = spanAttributes /** - * An array of the parent `span_ids` of this experiment event. This should be empty for the root - * span of a trace, and should most often contain just one parent element for subspans + * Returns the raw JSON value of [spanParents]. + * + * Unlike [spanParents], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("span_parents") @ExcludeMissing fun _spanParents() = spanParents + @JsonProperty("span_parents") + @ExcludeMissing + fun _spanParents(): JsonField> = spanParents - /** The `span_id` of the root of the trace this experiment event belongs to */ - @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId() = rootSpanId + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") @ExcludeMissing fun _spanAttributes() = spanAttributes + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ExperimentEvent = apply { - if (!validated) { - id() - datasetRecordId() - _xactId() - created() - projectId() - experimentId() - input() - output() - expected() - error() - scores()?.validate() - metadata()?.validate() - tags() - metrics()?.validate() - context()?.validate() - spanId() - spanParents() - rootSpanId() - spanAttributes()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExperimentEvent && - this.id == other.id && - this.datasetRecordId == other.datasetRecordId && - this._xactId == other._xactId && - this.created == other.created && - this.projectId == other.projectId && - this.experimentId == other.experimentId && - this.input == other.input && - this.output == other.output && - this.expected == other.expected && - this.error == other.error && - this.scores == other.scores && - this.metadata == other.metadata && - this.tags == other.tags && - this.metrics == other.metrics && - this.context == other.context && - this.spanId == other.spanId && - this.spanParents == other.spanParents && - this.rootSpanId == other.rootSpanId && - this.spanAttributes == other.spanAttributes && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - datasetRecordId, - _xactId, - created, - projectId, - experimentId, - input, - output, - expected, - error, - scores, - metadata, - tags, - metrics, - context, - spanId, - spanParents, - rootSpanId, - spanAttributes, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ExperimentEvent{id=$id, datasetRecordId=$datasetRecordId, _xactId=$_xactId, created=$created, projectId=$projectId, experimentId=$experimentId, input=$input, output=$output, expected=$expected, error=$error, scores=$scores, metadata=$metadata, tags=$tags, metrics=$metrics, context=$context, spanId=$spanId, spanParents=$spanParents, rootSpanId=$rootSpanId, spanAttributes=$spanAttributes, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ExperimentEvent]. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .created() + * .experimentId() + * .projectId() + * .rootSpanId() + * .spanId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ExperimentEvent]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var datasetRecordId: JsonField = JsonMissing.of() - private var _xactId: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var experimentId: JsonField = JsonMissing.of() - private var input: JsonValue = JsonMissing.of() - private var output: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() + private var id: JsonField? = null + private var _xactId: JsonField? = null + private var created: JsonField? = null + private var experimentId: JsonField? = null + private var projectId: JsonField? = null + private var rootSpanId: JsonField? = null + private var spanId: JsonField? = null + private var context: JsonField = JsonMissing.of() private var error: JsonValue = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() + private var expected: JsonValue = JsonMissing.of() + private var input: JsonValue = JsonMissing.of() + private var isRoot: JsonField = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() private var metrics: JsonField = JsonMissing.of() - private var context: JsonField = JsonMissing.of() - private var spanId: JsonField = JsonMissing.of() - private var spanParents: JsonField> = JsonMissing.of() - private var rootSpanId: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var output: JsonValue = JsonMissing.of() + private var scores: JsonField = JsonMissing.of() private var spanAttributes: JsonField = JsonMissing.of() + private var spanParents: JsonField>? = null + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(experimentEvent: ExperimentEvent) = apply { - this.id = experimentEvent.id - this.datasetRecordId = experimentEvent.datasetRecordId - this._xactId = experimentEvent._xactId - this.created = experimentEvent.created - this.projectId = experimentEvent.projectId - this.experimentId = experimentEvent.experimentId - this.input = experimentEvent.input - this.output = experimentEvent.output - this.expected = experimentEvent.expected - this.error = experimentEvent.error - this.scores = experimentEvent.scores - this.metadata = experimentEvent.metadata - this.tags = experimentEvent.tags - this.metrics = experimentEvent.metrics - this.context = experimentEvent.context - this.spanId = experimentEvent.spanId - this.spanParents = experimentEvent.spanParents - this.rootSpanId = experimentEvent.rootSpanId - this.spanAttributes = experimentEvent.spanAttributes - additionalProperties(experimentEvent.additionalProperties) + id = experimentEvent.id + _xactId = experimentEvent._xactId + created = experimentEvent.created + experimentId = experimentEvent.experimentId + projectId = experimentEvent.projectId + rootSpanId = experimentEvent.rootSpanId + spanId = experimentEvent.spanId + context = experimentEvent.context + error = experimentEvent.error + expected = experimentEvent.expected + input = experimentEvent.input + isRoot = experimentEvent.isRoot + metadata = experimentEvent.metadata + metrics = experimentEvent.metrics + origin = experimentEvent.origin + output = experimentEvent.output + scores = experimentEvent.scores + spanAttributes = experimentEvent.spanAttributes + spanParents = experimentEvent.spanParents.map { it.toMutableList() } + tags = experimentEvent.tags.map { it.toMutableList() } + additionalProperties = experimentEvent.additionalProperties.toMutableMap() } /** @@ -425,27 +485,12 @@ private constructor( fun id(id: String) = id(JsonField.of(id)) /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - fun datasetRecordId(datasetRecordId: String) = - datasetRecordId(JsonField.of(datasetRecordId)) - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to + * 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. */ - @JsonProperty("dataset_record_id") - @ExcludeMissing - fun datasetRecordId(datasetRecordId: JsonField) = apply { - this.datasetRecordId = datasetRecordId - } + fun id(id: JsonField) = apply { this.id = id } /** * The transaction id of an event is unique to the network operation that processed the @@ -455,60 +500,95 @@ private constructor( fun _xactId(_xactId: String) = _xactId(JsonField.of(_xactId)) /** - * The transaction id of an event is unique to the network operation that processed the - * event insertion. Transaction ids are monotonically increasing over time and can be used - * to retrieve a versioned snapshot of the experiment (see the `version` parameter) + * Sets [Builder._xactId] to an arbitrary JSON value. + * + * You should usually call [Builder._xactId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("_xact_id") - @ExcludeMissing fun _xactId(_xactId: JsonField) = apply { this._xactId = _xactId } /** The timestamp the experiment event was created */ fun created(created: OffsetDateTime) = created(JsonField.of(created)) - /** The timestamp the experiment event was created */ - @JsonProperty("created") - @ExcludeMissing + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } - /** Unique identifier for the project that the experiment belongs under */ - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - /** Unique identifier for the project that the experiment belongs under */ - @JsonProperty("project_id") - @ExcludeMissing - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } - /** Unique identifier for the experiment */ fun experimentId(experimentId: String) = experimentId(JsonField.of(experimentId)) - /** Unique identifier for the experiment */ - @JsonProperty("experiment_id") - @ExcludeMissing + /** + * Sets [Builder.experimentId] to an arbitrary JSON value. + * + * You should usually call [Builder.experimentId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun experimentId(experimentId: JsonField) = apply { this.experimentId = experimentId } + /** Unique identifier for the project that the experiment belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) + /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same - * between experiments, so they should not contain experiment-specific state. A simple rule - * of thumb is that if you run the same experiment twice, the `input` should be identical + * 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. */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } + fun projectId(projectId: JsonField) = apply { this.projectId = projectId } + + /** A unique identifier for the trace this experiment event belongs to */ + fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object), that allows you to determine whether the result is correct or not. - * For example, in an app that generates SQL queries, the `output` should be the _result_ of - * the SQL query generated by the model, not the query itself, because there may be multiple - * valid queries that answer a single question + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - @JsonProperty("output") - @ExcludeMissing - fun output(output: JsonValue) = apply { this.output = output } + fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + + /** + * A unique identifier used to link different experiment events together as part of a full + * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full + * details on tracing + */ + fun spanId(spanId: String) = spanId(JsonField.of(spanId)) + + /** + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } + + /** + * Context is additional information about the code that produced the experiment event. It + * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to + * track the location in code which produced the experiment event + */ + fun context(context: Context?) = context(JsonField.ofNullable(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 } + + /** The error that occurred, if any. */ + fun error(error: JsonValue) = apply { this.error = error } /** * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to @@ -518,38 +598,33 @@ private constructor( * while digging into analyses. However, we may later use these values to re-score outputs * or fine-tune your models */ - @JsonProperty("expected") - @ExcludeMissing fun expected(expected: JsonValue) = apply { this.expected = expected } - /** The error that occurred, if any. */ - @JsonProperty("error") - @ExcludeMissing - fun error(error: JsonValue) = apply { this.error = error } + /** + * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). + * Later on, Braintrust will use the `input` to know whether two test cases are the same + * between experiments, so they should not contain experiment-specific state. A simple rule + * of thumb is that if you run the same experiment twice, the `input` should be identical + */ + fun input(input: JsonValue) = apply { this.input = input } + + /** Whether this span is a root span */ + fun isRoot(isRoot: Boolean?) = isRoot(JsonField.ofNullable(isRoot)) /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare experiments + * Alias for [Builder.isRoot]. + * + * This unboxed primitive overload exists for backwards compatibility. */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) + fun isRoot(isRoot: Boolean) = isRoot(isRoot as Boolean?) /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare experiments + * Sets [Builder.isRoot] to an arbitrary JSON value. + * + * You should usually call [Builder.isRoot] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } + fun isRoot(isRoot: JsonField) = apply { this.isRoot = isRoot } /** * A dictionary with additional data about the test example, model outputs, or just about @@ -558,304 +633,509 @@ private constructor( * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, * but its keys must be strings */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings + * 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. */ - @JsonProperty("metadata") - @ExcludeMissing fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - /** * Metrics are numerical measurements tracking the execution of the code that produced the * experiment event. Use "start" and "end" to track the time span over which the experiment * event was produced */ - fun metrics(metrics: Metrics) = metrics(JsonField.of(metrics)) + fun metrics(metrics: Metrics?) = metrics(JsonField.ofNullable(metrics)) /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced + * Sets [Builder.metrics] to an arbitrary JSON value. + * + * You should usually call [Builder.metrics] with a well-typed [Metrics] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("metrics") - @ExcludeMissing fun metrics(metrics: JsonField) = apply { this.metrics = metrics } + /** Indicates the event was copied from another object. */ + fun origin(origin: ObjectReference?) = origin(JsonField.ofNullable(origin)) + /** - * Context is additional information about the code that produced the experiment event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the experiment event + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [ObjectReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun context(context: Context) = context(JsonField.of(context)) + fun origin(origin: JsonField) = apply { this.origin = origin } /** - * Context is additional information about the code that produced the experiment event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the experiment event + * The output of your application, including post-processing (an arbitrary, JSON + * serializable object), that allows you to determine whether the result is correct or not. + * For example, in an app that generates SQL queries, the `output` should be the _result_ of + * the SQL query generated by the model, not the query itself, because there may be multiple + * valid queries that answer a single question */ - @JsonProperty("context") - @ExcludeMissing - fun context(context: JsonField) = apply { this.context = context } + fun output(output: JsonValue) = apply { this.output = output } /** - * A unique identifier used to link different experiment events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a + * variety of signals that help you determine how accurate the outputs are compared to what + * you expect and diagnose failures. For example, a summarization app might have one score + * that tells you how accurate the summary is, and another that measures the word similarity + * between the generated and grouth truth summary. The word similarity score could help you + * determine whether the summarization was covering similar concepts or not. You can use + * these scores to help you sort, filter, and compare experiments */ - fun spanId(spanId: String) = spanId(JsonField.of(spanId)) + fun scores(scores: Scores?) = scores(JsonField.ofNullable(scores)) /** - * A unique identifier used to link different experiment events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("span_id") - @ExcludeMissing - fun spanId(spanId: JsonField) = apply { this.spanId = spanId } + fun scores(scores: JsonField) = apply { this.scores = scores } + + /** Human-identifying attributes of the span, such as name, type, etc. */ + fun spanAttributes(spanAttributes: SpanAttributes?) = + spanAttributes(JsonField.ofNullable(spanAttributes)) /** - * An array of the parent `span_ids` of this experiment event. This should be empty for the - * root span of a trace, and should most often contain just one parent element for subspans + * Sets [Builder.spanAttributes] to an arbitrary JSON value. + * + * You should usually call [Builder.spanAttributes] with a well-typed [SpanAttributes] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun spanParents(spanParents: List) = spanParents(JsonField.of(spanParents)) + fun spanAttributes(spanAttributes: JsonField) = apply { + this.spanAttributes = spanAttributes + } /** * An array of the parent `span_ids` of this experiment event. This should be empty for the * root span of a trace, and should most often contain just one parent element for subspans */ - @JsonProperty("span_parents") - @ExcludeMissing + fun spanParents(spanParents: List?) = spanParents(JsonField.ofNullable(spanParents)) + + /** + * Sets [Builder.spanParents] to an arbitrary JSON value. + * + * You should usually call [Builder.spanParents] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun spanParents(spanParents: JsonField>) = apply { - this.spanParents = spanParents + this.spanParents = spanParents.map { it.toMutableList() } } - /** The `span_id` of the root of the trace this experiment event belongs to */ - fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) + /** + * Adds a single [String] to [spanParents]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSpanParent(spanParent: String) = apply { + spanParents = + (spanParents ?: JsonField.of(mutableListOf())).also { + checkKnown("spanParents", it).add(spanParent) + } + } - /** The `span_id` of the root of the trace this experiment event belongs to */ - @JsonProperty("root_span_id") - @ExcludeMissing - fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(spanAttributes: SpanAttributes) = - spanAttributes(JsonField.of(spanAttributes)) + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") - @ExcludeMissing - fun spanAttributes(spanAttributes: JsonField) = apply { - this.spanAttributes = spanAttributes + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ExperimentEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .created() + * .experimentId() + * .projectId() + * .rootSpanId() + * .spanId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ExperimentEvent = ExperimentEvent( - id, - datasetRecordId, - _xactId, - created, - projectId, - experimentId, - input, - output, - expected, + checkRequired("id", id), + checkRequired("_xactId", _xactId), + checkRequired("created", created), + checkRequired("experimentId", experimentId), + checkRequired("projectId", projectId), + checkRequired("rootSpanId", rootSpanId), + checkRequired("spanId", spanId), + context, error, - scores, + expected, + input, + isRoot, metadata, - tags.map { it.toUnmodifiable() }, metrics, - context, - spanId, - spanParents.map { it.toUnmodifiable() }, - rootSpanId, + origin, + output, + scores, spanAttributes, - additionalProperties.toUnmodifiable(), + (spanParents ?: JsonMissing.of()).map { it.toImmutable() }, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): ExperimentEvent = apply { + if (validated) { + return@apply + } + + id() + _xactId() + created() + experimentId() + projectId() + rootSpanId() + spanId() + context()?.validate() + isRoot() + metadata()?.validate() + metrics()?.validate() + origin()?.validate() + scores()?.validate() + spanAttributes()?.validate() + spanParents() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_xactId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (experimentId.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (if (spanId.asKnown() == null) 0 else 1) + + (context.asKnown()?.validity() ?: 0) + + (if (isRoot.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (metrics.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (scores.asKnown()?.validity() ?: 0) + + (spanAttributes.asKnown()?.validity() ?: 0) + + (spanParents.asKnown()?.size ?: 0) + + (tags.asKnown()?.size ?: 0) + /** * Context is additional information about the code that produced the experiment event. It is * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the * location in code which produced the experiment event */ - @JsonDeserialize(builder = Context.Builder::class) - @NoAutoDetect class Context + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val callerFunctionname: JsonField, private val callerFilename: JsonField, + private val callerFunctionname: JsonField, private val callerLineno: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonField = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonField = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonField = JsonMissing.of(), + ) : this(callerFilename, callerFunctionname, callerLineno, mutableMapOf()) - private var hashCode: Int = 0 + /** + * Name of the file in code where the experiment event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - /** The function in code which created the experiment event */ + /** + * The function in code which created the experiment event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") - /** Name of the file in code where the experiment event was created */ - fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - - /** Line of code where the experiment event was created */ + /** + * Line of code where the experiment event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") - /** The function in code which created the experiment event */ + /** + * Returns the raw JSON value of [callerFilename]. + * + * Unlike [callerFilename], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonField = callerFilename + + /** + * Returns the raw JSON value of [callerFunctionname]. + * + * Unlike [callerFunctionname], this method doesn't throw if the JSON field has an + * unexpected type. + */ @JsonProperty("caller_functionname") @ExcludeMissing - fun _callerFunctionname() = callerFunctionname + fun _callerFunctionname(): JsonField = callerFunctionname - /** Name of the file in code where the experiment event was created */ - @JsonProperty("caller_filename") @ExcludeMissing fun _callerFilename() = callerFilename + /** + * Returns the raw JSON value of [callerLineno]. + * + * Unlike [callerLineno], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_lineno") + @ExcludeMissing + fun _callerLineno(): JsonField = callerLineno - /** Line of code where the experiment event was created */ - @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno() = callerLineno + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Context = apply { - if (!validated) { - callerFunctionname() - callerFilename() - callerLineno() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Context && - this.callerFunctionname == other.callerFunctionname && - this.callerFilename == other.callerFilename && - this.callerLineno == other.callerLineno && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Context{callerFunctionname=$callerFunctionname, callerFilename=$callerFilename, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Context]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Context]. */ + class Builder internal constructor() { - private var callerFunctionname: JsonField = JsonMissing.of() private var callerFilename: JsonField = JsonMissing.of() + private var callerFunctionname: JsonField = JsonMissing.of() private var callerLineno: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(context: Context) = apply { - this.callerFunctionname = context.callerFunctionname - this.callerFilename = context.callerFilename - this.callerLineno = context.callerLineno - additionalProperties(context.additionalProperties) - } - - /** The function in code which created the experiment event */ - fun callerFunctionname(callerFunctionname: String) = - callerFunctionname(JsonField.of(callerFunctionname)) - - /** The function in code which created the experiment event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun callerFunctionname(callerFunctionname: JsonField) = apply { - this.callerFunctionname = callerFunctionname + callerFilename = context.callerFilename + callerFunctionname = context.callerFunctionname + callerLineno = context.callerLineno + additionalProperties = context.additionalProperties.toMutableMap() } /** Name of the file in code where the experiment event was created */ - fun callerFilename(callerFilename: String) = - callerFilename(JsonField.of(callerFilename)) + fun callerFilename(callerFilename: String?) = + callerFilename(JsonField.ofNullable(callerFilename)) - /** Name of the file in code where the experiment event was created */ - @JsonProperty("caller_filename") - @ExcludeMissing + /** + * Sets [Builder.callerFilename] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFilename] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun callerFilename(callerFilename: JsonField) = apply { this.callerFilename = callerFilename } - /** Line of code where the experiment event was created */ - fun callerLineno(callerLineno: Long) = callerLineno(JsonField.of(callerLineno)) + /** The function in code which created the experiment event */ + fun callerFunctionname(callerFunctionname: String?) = + callerFunctionname(JsonField.ofNullable(callerFunctionname)) + + /** + * Sets [Builder.callerFunctionname] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFunctionname] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerFunctionname(callerFunctionname: JsonField) = apply { + this.callerFunctionname = callerFunctionname + } /** Line of code where the experiment event was created */ - @JsonProperty("caller_lineno") - @ExcludeMissing + fun callerLineno(callerLineno: Long?) = callerLineno(JsonField.ofNullable(callerLineno)) + + /** + * Alias for [Builder.callerLineno]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun callerLineno(callerLineno: Long) = callerLineno(callerLineno as Long?) + + /** + * Sets [Builder.callerLineno] to an arbitrary JSON value. + * + * You should usually call [Builder.callerLineno] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun callerLineno(callerLineno: JsonField) = apply { this.callerLineno = callerLineno } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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. + */ fun build(): Context = Context( - callerFunctionname, callerFilename, + callerFunctionname, callerLineno, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): Context = apply { + if (validated) { + return@apply + } + + callerFilename() + callerFunctionname() + callerLineno() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (callerFilename.asKnown() == null) 0 else 1) + + (if (callerFunctionname.asKnown() == null) 0 else 1) + + (if (callerLineno.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Context && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(callerFilename, callerFunctionname, callerLineno, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Context{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" } /** @@ -865,75 +1145,144 @@ private constructor( * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys * must be strings */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val additionalProperties: Map, + private val model: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of() + ) : this(model, mutableMapOf()) - fun toBuilder() = Builder().from(this) + /** + * The model used for this example + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): String? = model.getNullable("model") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * 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 - return other is Metadata && this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { + private var model: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + model = metadata.model + additionalProperties = metadata.additionalProperties.toMutableMap() } + /** The model used for this example */ + fun model(model: String?) = model(JsonField.ofNullable(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 additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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(model, additionalProperties.toMutableMap()) } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + model() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (model.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && + model == other.model && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(model, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metadata{model=$model, additionalProperties=$additionalProperties}" } /** @@ -941,525 +1290,593 @@ private constructor( * experiment event. Use "start" and "end" to track the time span over which the experiment * event was produced */ - @JsonDeserialize(builder = Metrics.Builder::class) - @NoAutoDetect class Metrics + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val start: JsonField, + private val callerFilename: JsonValue, + private val callerFunctionname: JsonValue, + private val callerLineno: JsonValue, + private val completionTokens: JsonField, private val end: JsonField, private val promptTokens: JsonField, - private val completionTokens: JsonField, + private val start: JsonField, private val tokens: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonValue = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonValue = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonValue = JsonMissing.of(), + @JsonProperty("completion_tokens") + @ExcludeMissing + completionTokens: JsonField = JsonMissing.of(), + @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), + @JsonProperty("prompt_tokens") + @ExcludeMissing + promptTokens: JsonField = JsonMissing.of(), + @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), + @JsonProperty("tokens") @ExcludeMissing tokens: JsonField = JsonMissing.of(), + ) : this( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + mutableMapOf(), + ) + + /** This metric is deprecated */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonValue = callerFilename - private var hashCode: Int = 0 + /** This metric is deprecated */ + @JsonProperty("caller_functionname") + @ExcludeMissing + fun _callerFunctionname(): JsonValue = callerFunctionname + + /** This metric is deprecated */ + @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno(): JsonValue = callerLineno /** - * A unix timestamp recording when the section of code which produced the experiment event - * started + * The number of tokens in the completion generated by the model (only set if this is an LLM + * span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun start(): Double? = start.getNullable("start") + fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") /** * A unix timestamp recording when the section of code which produced the experiment event * finished + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ fun end(): Double? = end.getNullable("end") /** * The number of tokens in the prompt used to generate the experiment event (only set if * this is an LLM span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) + * A unix timestamp recording when the section of code which produced the experiment event + * started + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") + fun start(): Double? = start.getNullable("start") - /** The total number of tokens in the input and output of the experiment event. */ + /** + * The total number of tokens in the input and output of the experiment event. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ fun tokens(): Long? = tokens.getNullable("tokens") /** - * A unix timestamp recording when the section of code which produced the experiment event - * started + * Returns the raw JSON value of [completionTokens]. + * + * Unlike [completionTokens], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("start") @ExcludeMissing fun _start() = start + @JsonProperty("completion_tokens") + @ExcludeMissing + fun _completionTokens(): JsonField = completionTokens /** - * A unix timestamp recording when the section of code which produced the experiment event - * finished + * Returns the raw JSON value of [end]. + * + * Unlike [end], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("end") @ExcludeMissing fun _end() = end + @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) + * Returns the raw JSON value of [promptTokens]. + * + * Unlike [promptTokens], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("prompt_tokens") @ExcludeMissing fun _promptTokens() = promptTokens + @JsonProperty("prompt_tokens") + @ExcludeMissing + fun _promptTokens(): JsonField = promptTokens /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) + * Returns the raw JSON value of [start]. + * + * Unlike [start], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun _completionTokens() = completionTokens + @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start + + /** + * Returns the raw JSON value of [tokens]. + * + * Unlike [tokens], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tokens") @ExcludeMissing fun _tokens(): JsonField = tokens - /** The total number of tokens in the input and output of the experiment event. */ - @JsonProperty("tokens") @ExcludeMissing fun _tokens() = tokens + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metrics = apply { - if (!validated) { - start() - end() - promptTokens() - completionTokens() - tokens() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metrics && - this.start == other.start && - this.end == other.end && - this.promptTokens == other.promptTokens && - this.completionTokens == other.completionTokens && - this.tokens == other.tokens && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Metrics{start=$start, end=$end, promptTokens=$promptTokens, completionTokens=$completionTokens, tokens=$tokens, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metrics]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metrics]. */ + class Builder internal constructor() { - private var start: JsonField = JsonMissing.of() + private var callerFilename: JsonValue = JsonMissing.of() + private var callerFunctionname: JsonValue = JsonMissing.of() + private var callerLineno: JsonValue = JsonMissing.of() + private var completionTokens: JsonField = JsonMissing.of() private var end: JsonField = JsonMissing.of() private var promptTokens: JsonField = JsonMissing.of() - private var completionTokens: JsonField = JsonMissing.of() + private var start: JsonField = JsonMissing.of() private var tokens: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metrics: Metrics) = apply { - this.start = metrics.start - this.end = metrics.end - this.promptTokens = metrics.promptTokens - this.completionTokens = metrics.completionTokens - this.tokens = metrics.tokens - additionalProperties(metrics.additionalProperties) + callerFilename = metrics.callerFilename + callerFunctionname = metrics.callerFunctionname + callerLineno = metrics.callerLineno + completionTokens = metrics.completionTokens + end = metrics.end + promptTokens = metrics.promptTokens + start = metrics.start + tokens = metrics.tokens + additionalProperties = metrics.additionalProperties.toMutableMap() + } + + /** This metric is deprecated */ + fun callerFilename(callerFilename: JsonValue) = apply { + this.callerFilename = callerFilename + } + + /** This metric is deprecated */ + fun callerFunctionname(callerFunctionname: JsonValue) = apply { + this.callerFunctionname = callerFunctionname } + /** This metric is deprecated */ + fun callerLineno(callerLineno: JsonValue) = apply { this.callerLineno = callerLineno } + /** - * A unix timestamp recording when the section of code which produced the experiment - * event started + * The number of tokens in the completion generated by the model (only set if this is an + * LLM span) */ - fun start(start: Double) = start(JsonField.of(start)) + fun completionTokens(completionTokens: Long?) = + completionTokens(JsonField.ofNullable(completionTokens)) /** - * A unix timestamp recording when the section of code which produced the experiment - * event started + * Alias for [Builder.completionTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. */ - @JsonProperty("start") - @ExcludeMissing - fun start(start: JsonField) = apply { this.start = start } + fun completionTokens(completionTokens: Long) = + completionTokens(completionTokens as Long?) /** - * A unix timestamp recording when the section of code which produced the experiment - * event finished + * Sets [Builder.completionTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.completionTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun end(end: Double) = end(JsonField.of(end)) + fun completionTokens(completionTokens: JsonField) = apply { + this.completionTokens = completionTokens + } /** * A unix timestamp recording when the section of code which produced the experiment * event finished */ - @JsonProperty("end") - @ExcludeMissing + fun end(end: Double?) = end(JsonField.ofNullable(end)) + + /** + * Alias for [Builder.end]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun end(end: Double) = end(end as Double?) + + /** + * Sets [Builder.end] to an arbitrary JSON value. + * + * You should usually call [Builder.end] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun end(end: JsonField) = apply { this.end = end } /** * The number of tokens in the prompt used to generate the experiment event (only set if * this is an LLM span) */ - fun promptTokens(promptTokens: Long) = promptTokens(JsonField.of(promptTokens)) + fun promptTokens(promptTokens: Long?) = promptTokens(JsonField.ofNullable(promptTokens)) /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) + * Alias for [Builder.promptTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun promptTokens(promptTokens: Long) = promptTokens(promptTokens as Long?) + + /** + * Sets [Builder.promptTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.promptTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("prompt_tokens") - @ExcludeMissing fun promptTokens(promptTokens: JsonField) = apply { this.promptTokens = promptTokens } /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) + * A unix timestamp recording when the section of code which produced the experiment + * event started */ - fun completionTokens(completionTokens: Long) = - completionTokens(JsonField.of(completionTokens)) + fun start(start: Double?) = start(JsonField.ofNullable(start)) /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) + * Alias for [Builder.start]. + * + * This unboxed primitive overload exists for backwards compatibility. */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun completionTokens(completionTokens: JsonField) = apply { - this.completionTokens = completionTokens - } + fun start(start: Double) = start(start as Double?) - /** The total number of tokens in the input and output of the experiment event. */ - fun tokens(tokens: Long) = tokens(JsonField.of(tokens)) + /** + * Sets [Builder.start] to an arbitrary JSON value. + * + * You should usually call [Builder.start] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun start(start: JsonField) = apply { this.start = start } /** The total number of tokens in the input and output of the experiment event. */ - @JsonProperty("tokens") - @ExcludeMissing + fun tokens(tokens: Long?) = tokens(JsonField.ofNullable(tokens)) + + /** + * Alias for [Builder.tokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun tokens(tokens: Long) = tokens(tokens as Long?) + + /** + * Sets [Builder.tokens] to an arbitrary JSON value. + * + * You should usually call [Builder.tokens] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun tokens(tokens: JsonField) = apply { this.tokens = tokens } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Metrics]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): Metrics = Metrics( - start, + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, end, promptTokens, - completionTokens, + start, tokens, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Metrics = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + completionTokens() + end() + promptTokens() + start() + tokens() + validated = true + } - fun validate(): Scores = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (completionTokens.asKnown() == null) 0 else 1) + + (if (end.asKnown() == null) 0 else 1) + + (if (promptTokens.asKnown() == null) 0 else 1) + + (if (start.asKnown() == null) 0 else 1) + + (if (tokens.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Scores && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode + return other is Metrics && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + completionTokens == other.completionTokens && + end == other.end && + promptTokens == other.promptTokens && + start == other.start && + tokens == other.tokens && + additionalProperties == other.additionalProperties } - override fun toString() = "Scores{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + private val hashCode: Int by lazy { + Objects.hash( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + additionalProperties, + ) } - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = hashCode - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) - } + override fun toString() = + "Metrics{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, completionTokens=$completionTokens, end=$end, promptTokens=$promptTokens, start=$start, tokens=$tokens, additionalProperties=$additionalProperties}" } - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonDeserialize(builder = SpanAttributes.Builder::class) - @NoAutoDetect - class SpanAttributes + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare experiments + */ + class Scores + @JsonCreator private constructor( - private val name: JsonField, - private val type: JsonField, - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Name of the span, for display purposes only */ - fun name(): String? = name.getNullable("name") - - /** Type of the span, for display purposes only */ - fun type(): Type? = type.getNullable("type") - - /** Name of the span, for display purposes only */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Type of the span, for display purposes only */ - @JsonProperty("type") @ExcludeMissing fun _type() = type - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): SpanAttributes = apply { - if (!validated) { - name() - type() - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SpanAttributes && - this.name == other.name && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SpanAttributes{name=$name, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Scores]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Scores]. */ + class Builder internal constructor() { - private var name: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(spanAttributes: SpanAttributes) = apply { - this.name = spanAttributes.name - this.type = spanAttributes.type - additionalProperties(spanAttributes.additionalProperties) + internal fun from(scores: Scores) = apply { + additionalProperties = scores.additionalProperties.toMutableMap() } - /** Name of the span, for display purposes only */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the span, for display purposes only */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - /** Type of the span, for display purposes only */ - fun type(type: Type) = type(JsonField.of(type)) - - /** Type of the span, for display purposes only */ - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): SpanAttributes = - SpanAttributes( - name, - type, - additionalProperties.toUnmodifiable(), - ) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns an immutable instance of [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Type && this.value == other.value + fun validate(): Scores = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { + validated = true + } - val LLM = Type(JsonField.of("llm")) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - val SCORE = Type(JsonField.of("score")) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - val FUNCTION = Type(JsonField.of("function")) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - val EVAL = Type(JsonField.of("eval")) + return other is Scores && additionalProperties == other.additionalProperties + } - val TASK = Type(JsonField.of("task")) + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - val TOOL = Type(JsonField.of("tool")) + override fun hashCode(): Int = hashCode - fun of(value: String) = Type(JsonField.of(value)) - } + override fun toString() = "Scores{additionalProperties=$additionalProperties}" + } - enum class Known { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - enum class Value { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - _UNKNOWN, - } + return other is ExperimentEvent && + id == other.id && + _xactId == other._xactId && + created == other.created && + experimentId == other.experimentId && + projectId == other.projectId && + rootSpanId == other.rootSpanId && + spanId == other.spanId && + context == other.context && + error == other.error && + expected == other.expected && + input == other.input && + isRoot == other.isRoot && + metadata == other.metadata && + metrics == other.metrics && + origin == other.origin && + output == other.output && + scores == other.scores && + spanAttributes == other.spanAttributes && + spanParents == other.spanParents && + tags == other.tags && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - LLM -> Value.LLM - SCORE -> Value.SCORE - FUNCTION -> Value.FUNCTION - EVAL -> Value.EVAL - TASK -> Value.TASK - TOOL -> Value.TOOL - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { + Objects.hash( + id, + _xactId, + created, + experimentId, + projectId, + rootSpanId, + spanId, + context, + error, + expected, + input, + isRoot, + metadata, + metrics, + origin, + output, + scores, + spanAttributes, + spanParents, + tags, + additionalProperties, + ) + } - fun known(): Known = - when (this) { - LLM -> Known.LLM - SCORE -> Known.SCORE - FUNCTION -> Known.FUNCTION - EVAL -> Known.EVAL - TASK -> Known.TASK - TOOL -> Known.TOOL - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "ExperimentEvent{id=$id, _xactId=$_xactId, created=$created, experimentId=$experimentId, projectId=$projectId, rootSpanId=$rootSpanId, spanId=$spanId, context=$context, error=$error, expected=$expected, input=$input, isRoot=$isRoot, metadata=$metadata, metrics=$metrics, origin=$origin, output=$output, scores=$scores, spanAttributes=$spanAttributes, spanParents=$spanParents, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParams.kt index 9fd90785..11b0dbf4 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParams.kt @@ -3,257 +3,462 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** Log feedback for a set of experiment events */ class ExperimentFeedbackParams -constructor( - private val experimentId: String, - private val feedback: List, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val experimentId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Experiment id */ + fun experimentId(): String? = experimentId + + /** + * A list of experiment feedback items + * + * @throws BraintrustInvalidDataException 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 feedback(): List = body.feedback() + + /** + * Returns the raw JSON value of [feedback]. + * + * Unlike [feedback], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _feedback(): JsonField> = body._feedback() + + 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 experimentId(): String = experimentId + fun toBuilder() = Builder().from(this) - fun feedback(): List = feedback + companion object { - internal fun getBody(): ExperimentFeedbackBody { - return ExperimentFeedbackBody(feedback, additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [ExperimentFeedbackParams]. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ExperimentFeedbackParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var experimentId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" + internal fun from(experimentFeedbackParams: ExperimentFeedbackParams) = apply { + experimentId = experimentFeedbackParams.experimentId + body = experimentFeedbackParams.body.toBuilder() + additionalHeaders = experimentFeedbackParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentFeedbackParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ExperimentFeedbackBody.Builder::class) - @NoAutoDetect - class ExperimentFeedbackBody - internal constructor( - private val feedback: List?, - private val additionalProperties: Map, - ) { + /** Experiment id */ + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } - private var hashCode: Int = 0 + /** + * 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: + * - [feedback] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** A list of experiment feedback items */ - @JsonProperty("feedback") fun feedback(): List? = feedback + fun feedback(feedback: List) = apply { body.feedback(feedback) } + + /** + * Sets [Builder.feedback] to an arbitrary JSON value. + * + * You should usually call [Builder.feedback] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun feedback(feedback: JsonField>) = apply { + body.feedback(feedback) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Adds a single [FeedbackExperimentItem] to [Builder.feedback]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFeedback(feedback: FeedbackExperimentItem) = apply { body.addFeedback(feedback) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ExperimentFeedbackBody && - this.feedback == other.feedback && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(feedback, additionalProperties) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "ExperimentFeedbackBody{feedback=$feedback, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var feedback: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(experimentFeedbackBody: ExperimentFeedbackBody) = apply { - this.feedback = experimentFeedbackBody.feedback - additionalProperties(experimentFeedbackBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** A list of experiment feedback items */ - @JsonProperty("feedback") - fun feedback(feedback: List) = apply { - this.feedback = feedback - } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun build(): ExperimentFeedbackBody = - ExperimentFeedbackBody( - checkNotNull(feedback) { "`feedback` is required but was not set" } - .toUnmodifiable(), - additionalProperties.toUnmodifiable() - ) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - return other is ExperimentFeedbackParams && - this.experimentId == other.experimentId && - this.feedback == other.feedback && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - experimentId, - feedback, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun toString() = - "ExperimentFeedbackParams{experimentId=$experimentId, feedback=$feedback, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - companion object { + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun builder() = Builder() - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - @NoAutoDetect - class Builder { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - private var experimentId: String? = null - private var feedback: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - internal fun from(experimentFeedbackParams: ExperimentFeedbackParams) = apply { - this.experimentId = experimentFeedbackParams.experimentId - this.feedback(experimentFeedbackParams.feedback) - additionalQueryParams(experimentFeedbackParams.additionalQueryParams) - additionalHeaders(experimentFeedbackParams.additionalHeaders) - additionalBodyProperties(experimentFeedbackParams.additionalBodyProperties) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + /** + * Returns an immutable instance of [ExperimentFeedbackParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExperimentFeedbackParams = + ExperimentFeedbackParams( + experimentId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } - /** A list of experiment feedback items */ - fun feedback(feedback: List) = apply { - this.feedback.clear() - this.feedback.addAll(feedback) + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + else -> "" } - /** A list of experiment feedback items */ - fun addFeedback(feedback: FeedbackExperimentItem) = apply { this.feedback.add(feedback) } + override fun _headers(): Headers = additionalHeaders - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + override fun _queryParams(): QueryParams = additionalQueryParams - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val feedback: JsonField>, + private val additionalProperties: MutableMap, + ) { - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + @JsonCreator + private constructor( + @JsonProperty("feedback") + @ExcludeMissing + feedback: JsonField> = JsonMissing.of() + ) : this(feedback, mutableMapOf()) + + /** + * A list of experiment feedback items + * + * @throws BraintrustInvalidDataException 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 feedback(): List = feedback.getRequired("feedback") + + /** + * Returns the raw JSON value of [feedback]. + * + * Unlike [feedback], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("feedback") + @ExcludeMissing + fun _feedback(): JsonField> = feedback - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun toBuilder() = Builder().from(this) - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + companion object { - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + */ + fun builder() = Builder() } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + private var feedback: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + internal fun from(body: Body) = apply { + feedback = body.feedback.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** A list of experiment feedback items */ + fun feedback(feedback: List) = feedback(JsonField.of(feedback)) + + /** + * Sets [Builder.feedback] to an arbitrary JSON value. + * + * You should usually call [Builder.feedback] with a well-typed + * `List` value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun feedback(feedback: JsonField>) = apply { + this.feedback = feedback.map { it.toMutableList() } + } + + /** + * Adds a single [FeedbackExperimentItem] to [Builder.feedback]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFeedback(feedback: FeedbackExperimentItem) = apply { + this.feedback = + (this.feedback ?: JsonField.of(mutableListOf())).also { + checkKnown("feedback", it).add(feedback) + } + } + + 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: + * ```kotlin + * .feedback() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("feedback", feedback).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + feedback().forEach { it.validate() } + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ExperimentFeedbackParams = - ExperimentFeedbackParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, - checkNotNull(feedback) { "`feedback` is required but was not set" } - .toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (feedback.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + feedback == other.feedback && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(feedback, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{feedback=$feedback, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExperimentFeedbackParams && + experimentId == other.experimentId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(experimentId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ExperimentFeedbackParams{experimentId=$experimentId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchParams.kt index 5c58fe6e..d09edd82 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchParams.kt @@ -2,115 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** + * Fetch the events in an experiment. Equivalent to the POST form of the same path, but with the + * parameters in the URL query rather than in the request body. For more complex queries, use the + * `POST /btql` endpoint. + */ class ExperimentFetchParams -constructor( - private val experimentId: String, +private constructor( + private val experimentId: String?, private val limit: Long?, private val maxRootSpanId: String?, private val maxXactId: String?, private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - - fun experimentId(): String = experimentId - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Experiment id */ + fun experimentId(): String? = experimentId + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, later + * pages may return rows which showed up in earlier pages, except with an earlier `_xact_id`. + * This happens because pagination occurs over the whole version history of the event log. You + * will most likely want to exclude any such duplicate, outdated rows (by `id`) from your + * combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up with + * more individual rows than the specified limit if you are fetching events containing traces. + */ fun limit(): Long? = limit + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + */ fun maxRootSpanId(): String? = maxRootSpanId + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + */ fun maxXactId(): String? = maxXactId + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use the + * `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + */ fun version(): String? = version - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.maxRootSpanId?.let { params.put("max_root_span_id", listOf(it.toString())) } - this.maxXactId?.let { params.put("max_xact_id", listOf(it.toString())) } - this.version?.let { params.put("version", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" - } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - return other is ExperimentFetchParams && - this.experimentId == other.experimentId && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - experimentId, - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "ExperimentFetchParams{experimentId=$experimentId, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ExperimentFetchParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ExperimentFetchParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ExperimentFetchParams]. */ + class Builder internal constructor() { private var experimentId: String? = null private var limit: Long? = null private var maxRootSpanId: String? = null private var maxXactId: String? = null private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(experimentFetchParams: ExperimentFetchParams) = apply { - this.experimentId = experimentFetchParams.experimentId - this.limit = experimentFetchParams.limit - this.maxRootSpanId = experimentFetchParams.maxRootSpanId - this.maxXactId = experimentFetchParams.maxXactId - this.version = experimentFetchParams.version - additionalQueryParams(experimentFetchParams.additionalQueryParams) - additionalHeaders(experimentFetchParams.additionalHeaders) + experimentId = experimentFetchParams.experimentId + limit = experimentFetchParams.limit + maxRootSpanId = experimentFetchParams.maxRootSpanId + maxXactId = experimentFetchParams.maxXactId + version = experimentFetchParams.version + additionalHeaders = experimentFetchParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentFetchParams.additionalQueryParams.toBuilder() } /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } /** * limit the number of traces fetched @@ -127,7 +133,14 @@ constructor( * with more individual rows than the specified limit if you are fetching events containing * traces. */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -141,7 +154,7 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } + fun maxRootSpanId(maxRootSpanId: String?) = apply { this.maxRootSpanId = maxRootSpanId } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -155,7 +168,7 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun maxXactId(maxXactId: String?) = apply { this.maxXactId = maxXactId } /** * Retrieve a snapshot of events from a past time @@ -163,57 +176,168 @@ constructor( * The version id is essentially a filter on the latest event transaction id. You can use * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. */ - fun version(version: String) = apply { this.version = version } + fun version(version: String?) = apply { this.version = version } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + 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 removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ExperimentFetchParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ExperimentFetchParams = ExperimentFetchParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, + experimentId, limit, maxRootSpanId, maxXactId, version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + limit?.let { put("limit", it.toString()) } + maxRootSpanId?.let { put("max_root_span_id", it) } + maxXactId?.let { put("max_xact_id", it) } + version?.let { put("version", it) } + putAll(additionalQueryParams) + } + .build() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExperimentFetchParams && + experimentId == other.experimentId && + limit == other.limit && + maxRootSpanId == other.maxRootSpanId && + maxXactId == other.maxXactId && + version == other.version && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + experimentId, + limit, + maxRootSpanId, + maxXactId, + version, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ExperimentFetchParams{experimentId=$experimentId, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParams.kt index ea8c04bf..b31ea239 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParams.kt @@ -3,81 +3,197 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Fetch the events in an experiment. Equivalent to the GET form of the same path, but with the + * parameters in the request body rather than in the URL query. For more complex queries, use the + * `POST /btql` endpoint. + */ class ExperimentFetchPostParams -constructor( - private val experimentId: String, - private val cursor: String?, - private val filters: List?, - private val limit: Long?, - private val maxRootSpanId: String?, - private val maxXactId: String?, - private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun experimentId(): String = experimentId - - fun cursor(): String? = cursor - - fun filters(): List? = filters - - fun limit(): Long? = limit - - fun maxRootSpanId(): String? = maxRootSpanId - - fun maxXactId(): String? = maxXactId - - fun version(): String? = version - - internal fun getBody(): ExperimentFetchPostBody { - return ExperimentFetchPostBody( - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalBodyProperties, - ) +private constructor( + private val experimentId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Experiment id */ + fun experimentId(): String? = experimentId + + /** + * An opaque string to be used as a cursor for the next page of results, in order from latest to + * earliest. + * + * The string can be obtained directly from the `cursor` property of the previous fetch query + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun cursor(): String? = body.cursor() + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, later + * pages may return rows which showed up in earlier pages, except with an earlier `_xact_id`. + * This happens because pagination occurs over the whole version history of the event log. You + * will most likely want to exclude any such duplicate, outdated rows (by `id`) from your + * combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up with + * more individual rows than the specified limit if you are fetching events containing traces. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun limit(): Long? = body.limit() + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun maxRootSpanId(): String? = body.maxRootSpanId() + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun maxXactId(): String? = body.maxXactId() + + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use the + * `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun version(): String? = body.version() + + /** + * Returns the raw JSON value of [cursor]. + * + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _cursor(): JsonField = body._cursor() + + /** + * Returns the raw JSON value of [limit]. + * + * Unlike [limit], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _limit(): JsonField = body._limit() + + /** + * Returns the raw JSON value of [maxRootSpanId]. + * + * Unlike [maxRootSpanId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _maxRootSpanId(): JsonField = body._maxRootSpanId() + + /** + * Returns the raw JSON value of [maxXactId]. + * + * Unlike [maxXactId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _maxXactId(): JsonField = body._maxXactId() + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _version(): JsonField = body._version() + + 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 { + + fun none(): ExperimentFetchPostParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [ExperimentFetchPostParams]. + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ExperimentFetchPostParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var experimentId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" + internal fun from(experimentFetchPostParams: ExperimentFetchPostParams) = apply { + experimentId = experimentFetchPostParams.experimentId + body = experimentFetchPostParams.body.toBuilder() + additionalHeaders = experimentFetchPostParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentFetchPostParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ExperimentFetchPostBody.Builder::class) - @NoAutoDetect - class ExperimentFetchPostBody - internal constructor( - private val cursor: String?, - private val filters: List?, - private val limit: Long?, - private val maxRootSpanId: String?, - private val maxXactId: String?, - private val version: String?, - private val additionalProperties: Map, - ) { + /** Experiment id */ + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } - private var hashCode: Int = 0 + /** + * 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: + * - [cursor] + * - [limit] + * - [maxRootSpanId] + * - [maxXactId] + * - [version] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** * An opaque string to be used as a cursor for the next page of results, in order from @@ -86,17 +202,15 @@ constructor( * The string can be obtained directly from the `cursor` property of the previous fetch * query */ - @JsonProperty("cursor") fun cursor(): String? = cursor + fun cursor(cursor: String?) = apply { body.cursor(cursor) } /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. + * Sets [Builder.cursor] to an arbitrary JSON value. * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. + * You should usually call [Builder.cursor] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("filters") fun filters(): List? = filters + fun cursor(cursor: JsonField) = apply { body.cursor(cursor) } /** * limit the number of traces fetched @@ -113,7 +227,22 @@ constructor( * with more individual rows than the specified limit if you are fetching events containing * traces. */ - @JsonProperty("limit") fun limit(): Long? = limit + fun limit(limit: Long?) = apply { body.limit(limit) } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** + * Sets [Builder.limit] to an arbitrary JSON value. + * + * You should usually call [Builder.limit] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun limit(limit: JsonField) = apply { body.limit(limit) } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -127,7 +256,18 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - @JsonProperty("max_root_span_id") fun maxRootSpanId(): String? = maxRootSpanId + fun maxRootSpanId(maxRootSpanId: String?) = apply { body.maxRootSpanId(maxRootSpanId) } + + /** + * Sets [Builder.maxRootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxRootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun maxRootSpanId(maxRootSpanId: JsonField) = apply { + body.maxRootSpanId(maxRootSpanId) + } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -141,7 +281,16 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - @JsonProperty("max_xact_id") fun maxXactId(): String? = maxXactId + fun maxXactId(maxXactId: String?) = apply { body.maxXactId(maxXactId) } + + /** + * Sets [Builder.maxXactId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxXactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun maxXactId(maxXactId: JsonField) = apply { body.maxXactId(maxXactId) } /** * Retrieve a snapshot of events from a past time @@ -149,71 +298,333 @@ constructor( * The version id is essentially a filter on the latest event transaction id. You can use * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. */ - @JsonProperty("version") fun version(): String? = version + fun version(version: String?) = apply { body.version(version) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun version(version: JsonField) = apply { body.version(version) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ExperimentFetchPostBody && - this.cursor == other.cursor && - this.filters == other.filters && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalProperties, - ) + 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) } - return hashCode + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - override fun toString() = - "ExperimentFetchPostBody{cursor=$cursor, filters=$filters, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalProperties=$additionalProperties}" + 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 [ExperimentFetchPostParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ExperimentFetchPostParams = + ExperimentFetchPostParams( + experimentId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cursor: JsonField, + private val limit: JsonField, + private val maxRootSpanId: JsonField, + private val maxXactId: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cursor") @ExcludeMissing cursor: JsonField = JsonMissing.of(), + @JsonProperty("limit") @ExcludeMissing limit: JsonField = JsonMissing.of(), + @JsonProperty("max_root_span_id") + @ExcludeMissing + maxRootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("max_xact_id") + @ExcludeMissing + maxXactId: JsonField = JsonMissing.of(), + @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of(), + ) : this(cursor, limit, maxRootSpanId, maxXactId, version, mutableMapOf()) + + /** + * An opaque string to be used as a cursor for the next page of results, in order from + * latest to earliest. + * + * The string can be obtained directly from the `cursor` property of the previous fetch + * query + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cursor(): String? = cursor.getNullable("cursor") + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, + * later pages may return rows which showed up in earlier pages, except with an earlier + * `_xact_id`. This happens because pagination occurs over the whole version history of the + * event log. You will most likely want to exclude any such duplicate, outdated rows (by + * `id`) from your combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up + * with more individual rows than the specified limit if you are fetching events containing + * traces. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun limit(): Long? = limit.getNullable("limit") + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of + * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' + * argument going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the + * cursor for the next page can be found as the row with the minimum (earliest) value of the + * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of + * paginating fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxRootSpanId(): String? = maxRootSpanId.getNullable("max_root_span_id") + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of + * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' + * argument going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the + * cursor for the next page can be found as the row with the minimum (earliest) value of the + * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of + * paginating fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxXactId(): String? = maxXactId.getNullable("max_xact_id") + + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use + * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun version(): String? = version.getNullable("version") + + /** + * Returns the raw JSON value of [cursor]. + * + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cursor") @ExcludeMissing fun _cursor(): JsonField = cursor + + /** + * Returns the raw JSON value of [limit]. + * + * Unlike [limit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("limit") @ExcludeMissing fun _limit(): JsonField = limit + + /** + * Returns the raw JSON value of [maxRootSpanId]. + * + * Unlike [maxRootSpanId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("max_root_span_id") + @ExcludeMissing + fun _maxRootSpanId(): JsonField = maxRootSpanId + + /** + * Returns the raw JSON value of [maxXactId]. + * + * Unlike [maxXactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("max_xact_id") @ExcludeMissing fun _maxXactId(): JsonField = maxXactId + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version + + @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]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Body]. */ + class Builder internal constructor() { - private var cursor: String? = null - private var filters: List? = null - private var limit: Long? = null - private var maxRootSpanId: String? = null - private var maxXactId: String? = null - private var version: String? = null + private var cursor: JsonField = JsonMissing.of() + private var limit: JsonField = JsonMissing.of() + private var maxRootSpanId: JsonField = JsonMissing.of() + private var maxXactId: JsonField = JsonMissing.of() + private var version: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(experimentFetchPostBody: ExperimentFetchPostBody) = apply { - this.cursor = experimentFetchPostBody.cursor - this.filters = experimentFetchPostBody.filters - this.limit = experimentFetchPostBody.limit - this.maxRootSpanId = experimentFetchPostBody.maxRootSpanId - this.maxXactId = experimentFetchPostBody.maxXactId - this.version = experimentFetchPostBody.version - additionalProperties(experimentFetchPostBody.additionalProperties) + internal fun from(body: Body) = apply { + cursor = body.cursor + limit = body.limit + maxRootSpanId = body.maxRootSpanId + maxXactId = body.maxXactId + version = body.version + additionalProperties = body.additionalProperties.toMutableMap() } /** @@ -223,18 +634,16 @@ constructor( * The string can be obtained directly from the `cursor` property of the previous fetch * query */ - @JsonProperty("cursor") fun cursor(cursor: String) = apply { this.cursor = cursor } + fun cursor(cursor: String?) = cursor(JsonField.ofNullable(cursor)) /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. + * Sets [Builder.cursor] to an arbitrary JSON value. * - * A list of filters on the events to fetch. Currently, only path-lookup type filters - * are supported. + * You should usually call [Builder.cursor] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("filters") - fun filters(filters: List) = apply { this.filters = filters } + fun cursor(cursor: JsonField) = apply { this.cursor = cursor } /** * limit the number of traces fetched @@ -251,7 +660,23 @@ constructor( * with more individual rows than the specified limit if you are fetching events * containing traces. */ - @JsonProperty("limit") fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = limit(JsonField.ofNullable(limit)) + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** + * Sets [Builder.limit] to an arbitrary JSON value. + * + * You should usually call [Builder.limit] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun limit(limit: JsonField) = apply { this.limit = limit } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor @@ -265,8 +690,19 @@ constructor( * the tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an * overview of paginating fetch queries. */ - @JsonProperty("max_root_span_id") - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } + fun maxRootSpanId(maxRootSpanId: String?) = + maxRootSpanId(JsonField.ofNullable(maxRootSpanId)) + + /** + * Sets [Builder.maxRootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxRootSpanId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxRootSpanId(maxRootSpanId: JsonField) = apply { + this.maxRootSpanId = maxRootSpanId + } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor @@ -280,8 +716,16 @@ constructor( * the tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an * overview of paginating fetch queries. */ - @JsonProperty("max_xact_id") - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun maxXactId(maxXactId: String?) = maxXactId(JsonField.ofNullable(maxXactId)) + + /** + * Sets [Builder.maxXactId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxXactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxXactId(maxXactId: JsonField) = apply { this.maxXactId = maxXactId } /** * Retrieve a snapshot of events from a past time @@ -290,265 +734,127 @@ constructor( * use the `max_xact_id` returned by a past fetch as the version to reproduce that exact * fetch. */ - @JsonProperty("version") fun version(version: String) = apply { this.version = version } + fun version(version: String?) = version(JsonField.ofNullable(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): ExperimentFetchPostBody = - ExperimentFetchPostBody( + 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( cursor, - filters?.toUnmodifiable(), limit, maxRootSpanId, maxXactId, version, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExperimentFetchPostParams && - this.experimentId == other.experimentId && - this.cursor == other.cursor && - this.filters == other.filters && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int { - return Objects.hash( - experimentId, - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } - - override fun toString() = - "ExperimentFetchPostParams{experimentId=$experimentId, cursor=$cursor, filters=$filters, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) - - companion object { - - fun builder() = Builder() - } - - @NoAutoDetect - class Builder { - - private var experimentId: String? = null - private var cursor: String? = null - private var filters: MutableList = mutableListOf() - private var limit: Long? = null - private var maxRootSpanId: String? = null - private var maxXactId: String? = null - private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() - - internal fun from(experimentFetchPostParams: ExperimentFetchPostParams) = apply { - this.experimentId = experimentFetchPostParams.experimentId - this.cursor = experimentFetchPostParams.cursor - this.filters(experimentFetchPostParams.filters ?: listOf()) - this.limit = experimentFetchPostParams.limit - this.maxRootSpanId = experimentFetchPostParams.maxRootSpanId - this.maxXactId = experimentFetchPostParams.maxXactId - this.version = experimentFetchPostParams.version - additionalQueryParams(experimentFetchPostParams.additionalQueryParams) - additionalHeaders(experimentFetchPostParams.additionalHeaders) - additionalBodyProperties(experimentFetchPostParams.additionalBodyProperties) - } - /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + private var validated: Boolean = false - /** - * An opaque string to be used as a cursor for the next page of results, in order from - * latest to earliest. - * - * The string can be obtained directly from the `cursor` property of the previous fetch - * query - */ - fun cursor(cursor: String) = apply { this.cursor = cursor } + fun validate(): Body = apply { + if (validated) { + return@apply + } - /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. - * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. - */ - fun filters(filters: List) = apply { - this.filters.clear() - this.filters.addAll(filters) + cursor() + limit() + maxRootSpanId() + maxXactId() + version() + validated = true } - /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. - * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. - */ - fun addFilter(filter: PathLookupFilter) = apply { this.filters.add(filter) } - - /** - * limit the number of traces fetched - * - * Fetch queries may be paginated if the total result size is expected to be large (e.g. - * project_logs which accumulate over a long time). Note that fetch queries only support - * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, - * later pages may return rows which showed up in earlier pages, except with an earlier - * `_xact_id`. This happens because pagination occurs over the whole version history of the - * event log. You will most likely want to exclude any such duplicate, outdated rows (by - * `id`) from your combined result set. - * - * The `limit` parameter controls the number of full traces to return. So you may end up - * with more individual rows than the specified limit if you are fetching events containing - * traces. - */ - fun limit(limit: Long) = apply { this.limit = limit } - - /** - * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of - * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' - * argument going forwards. - * - * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor - * - * Since a paginated fetch query returns results in order from latest to earliest, the - * cursor for the next page can be found as the row with the minimum (earliest) value of the - * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of - * paginating fetch queries. - */ - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } - - /** - * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of - * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' - * argument going forwards. - * - * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor - * - * Since a paginated fetch query returns results in order from latest to earliest, the - * cursor for the next page can be found as the row with the minimum (earliest) value of the - * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of - * paginating fetch queries. - */ - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } /** - * Retrieve a snapshot of events from a past time + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * The version id is essentially a filter on the latest event transaction id. You can use - * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * Used for best match union deserialization. */ - fun version(version: String) = apply { this.version = version } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + internal fun validity(): Int = + (if (cursor.asKnown() == null) 0 else 1) + + (if (limit.asKnown() == null) 0 else 1) + + (if (maxRootSpanId.asKnown() == null) 0 else 1) + + (if (maxXactId.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } - - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } - - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } - - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + return other is Body && + cursor == other.cursor && + limit == other.limit && + maxRootSpanId == other.maxRootSpanId && + maxXactId == other.maxXactId && + version == other.version && + additionalProperties == other.additionalProperties } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + private val hashCode: Int by lazy { + Objects.hash(cursor, limit, maxRootSpanId, maxXactId, version, additionalProperties) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + override fun hashCode(): Int = hashCode - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + override fun toString() = + "Body{cursor=$cursor, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalProperties=$additionalProperties}" + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) - } + return other is ExperimentFetchPostParams && + experimentId == other.experimentId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = + Objects.hash(experimentId, body, additionalHeaders, additionalQueryParams) - fun build(): ExperimentFetchPostParams = - ExperimentFetchPostParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, - cursor, - if (filters.size == 0) null else filters.toUnmodifiable(), - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + override fun toString() = + "ExperimentFetchPostParams{experimentId=$experimentId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentInsertParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentInsertParams.kt index d5e9a839..3962f57e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentInsertParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentInsertParams.kt @@ -2,402 +2,460 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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 +/** Insert a set of events into the experiment */ class ExperimentInsertParams -constructor( - private val experimentId: String, - private val events: List, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val experimentId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Experiment id */ + fun experimentId(): String? = experimentId + + /** + * A list of experiment events to insert + * + * @throws BraintrustInvalidDataException 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 events(): List = body.events() + + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _events(): JsonField> = body._events() + + 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 experimentId(): String = experimentId + fun toBuilder() = Builder().from(this) - fun events(): List = events + companion object { - internal fun getBody(): ExperimentInsertBody { - return ExperimentInsertBody(events, additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [ExperimentInsertParams]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ExperimentInsertParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var experimentId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" + internal fun from(experimentInsertParams: ExperimentInsertParams) = apply { + experimentId = experimentInsertParams.experimentId + body = experimentInsertParams.body.toBuilder() + additionalHeaders = experimentInsertParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentInsertParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ExperimentInsertBody.Builder::class) - @NoAutoDetect - class ExperimentInsertBody - internal constructor( - private val events: List?, - private val additionalProperties: Map, - ) { + /** Experiment id */ + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } - private var hashCode: Int = 0 + /** + * 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: + * - [events] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** A list of experiment events to insert */ - @JsonProperty("events") fun events(): List? = events - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun events(events: List) = apply { body.events(events) } + + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun events(events: JsonField>) = apply { body.events(events) } + + /** + * Adds a single [InsertExperimentEvent] to [events]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEvent(event: InsertExperimentEvent) = apply { body.addEvent(event) } - return other is ExperimentInsertBody && - this.events == other.events && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(events, additionalProperties) - } - return hashCode + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) } - override fun toString() = - "ExperimentInsertBody{events=$events, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - class Builder { - - private var events: List? = null - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(experimentInsertBody: ExperimentInsertBody) = apply { - this.events = experimentInsertBody.events - additionalProperties(experimentInsertBody.additionalProperties) - } - - /** A list of experiment events to insert */ - @JsonProperty("events") fun events(events: List) = apply { this.events = events } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - fun build(): ExperimentInsertBody = - ExperimentInsertBody( - checkNotNull(events) { "`events` is required but was not set" } - .toUnmodifiable(), - additionalProperties.toUnmodifiable() - ) + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ExperimentInsertParams && - this.experimentId == other.experimentId && - this.events == other.events && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - experimentId, - events, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "ExperimentInsertParams{experimentId=$experimentId, events=$events, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var experimentId: String? = null - private var events: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(experimentInsertParams: ExperimentInsertParams) = apply { - this.experimentId = experimentInsertParams.experimentId - this.events(experimentInsertParams.events) - additionalQueryParams(experimentInsertParams.additionalQueryParams) - additionalHeaders(experimentInsertParams.additionalHeaders) - additionalBodyProperties(experimentInsertParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** A list of experiment events to insert */ - fun events(events: List) = apply { - this.events.clear() - this.events.addAll(events) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - /** A list of experiment events to insert */ - fun addEvent(event: Event) = apply { this.events.add(event) } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - + /** + * Returns an immutable instance of [ExperimentInsertParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ExperimentInsertParams = ExperimentInsertParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, - checkNotNull(events) { "`events` is required but was not set" }.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + experimentId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Event.Deserializer::class) - @JsonSerialize(using = Event.Serializer::class) - class Event + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val insertExperimentEventReplace: InsertExperimentEventReplace? = null, - private val insertExperimentEventMerge: InsertExperimentEventMerge? = null, - private val _json: JsonValue? = null, + private val events: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("events") + @ExcludeMissing + events: JsonField> = JsonMissing.of() + ) : this(events, mutableMapOf()) + + /** + * A list of experiment events to insert + * + * @throws BraintrustInvalidDataException 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 events(): List = events.getRequired("events") + + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("events") + @ExcludeMissing + fun _events(): JsonField> = events - fun insertExperimentEventReplace(): InsertExperimentEventReplace? = - insertExperimentEventReplace + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - fun insertExperimentEventMerge(): InsertExperimentEventMerge? = insertExperimentEventMerge + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun isInsertExperimentEventReplace(): Boolean = insertExperimentEventReplace != null + fun toBuilder() = Builder().from(this) - fun isInsertExperimentEventMerge(): Boolean = insertExperimentEventMerge != null + companion object { - fun asInsertExperimentEventReplace(): InsertExperimentEventReplace = - insertExperimentEventReplace.getOrThrow("insertExperimentEventReplace") + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ + fun builder() = Builder() + } - fun asInsertExperimentEventMerge(): InsertExperimentEventMerge = - insertExperimentEventMerge.getOrThrow("insertExperimentEventMerge") + /** A builder for [Body]. */ + class Builder internal constructor() { - fun _json(): JsonValue? = _json + private var events: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun accept(visitor: Visitor): T { - return when { - insertExperimentEventReplace != null -> - visitor.visitInsertExperimentEventReplace(insertExperimentEventReplace) - insertExperimentEventMerge != null -> - visitor.visitInsertExperimentEventMerge(insertExperimentEventMerge) - else -> visitor.unknown(_json) + internal fun from(body: Body) = apply { + events = body.events.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() } - } - fun validate(): Event = apply { - if (!validated) { - if (insertExperimentEventReplace == null && insertExperimentEventMerge == null) { - throw BraintrustInvalidDataException("Unknown Event: $_json") - } - insertExperimentEventReplace?.validate() - insertExperimentEventMerge?.validate() - validated = true + /** A list of experiment events to insert */ + fun events(events: List) = events(JsonField.of(events)) + + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun events(events: JsonField>) = apply { + this.events = events.map { it.toMutableList() } } - } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** + * Adds a single [InsertExperimentEvent] to [events]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEvent(event: InsertExperimentEvent) = apply { + events = + (events ?: JsonField.of(mutableListOf())).also { + checkKnown("events", it).add(event) + } } - return other is Event && - this.insertExperimentEventReplace == other.insertExperimentEventReplace && - this.insertExperimentEventMerge == other.insertExperimentEventMerge - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - override fun hashCode(): Int { - return Objects.hash(insertExperimentEventReplace, insertExperimentEventMerge) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - override fun toString(): String { - return when { - insertExperimentEventReplace != null -> - "Event{insertExperimentEventReplace=$insertExperimentEventReplace}" - insertExperimentEventMerge != null -> - "Event{insertExperimentEventMerge=$insertExperimentEventMerge}" - _json != null -> "Event{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Event") + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) } - } - companion object { + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun ofInsertExperimentEventReplace( - insertExperimentEventReplace: InsertExperimentEventReplace - ) = Event(insertExperimentEventReplace = insertExperimentEventReplace) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun ofInsertExperimentEventMerge( - insertExperimentEventMerge: InsertExperimentEventMerge - ) = Event(insertExperimentEventMerge = insertExperimentEventMerge) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("events", events).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - interface Visitor { - - fun visitInsertExperimentEventReplace( - insertExperimentEventReplace: InsertExperimentEventReplace - ): T - - fun visitInsertExperimentEventMerge( - insertExperimentEventMerge: InsertExperimentEventMerge - ): T + private var validated: Boolean = false - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Event: $json") + fun validate(): Body = apply { + if (validated) { + return@apply } + + events().forEach { it.validate() } + validated = true } - class Deserializer : BaseDeserializer(Event::class) { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - override fun ObjectCodec.deserialize(node: JsonNode): Event { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { - it.validate() - } - ?.let { - return Event(insertExperimentEventReplace = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Event(insertExperimentEventMerge = it, _json = json) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (events.asKnown()?.sumOf { it.validity().toInt() } ?: 0) - return Event(_json = json) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Body && + events == other.events && + additionalProperties == other.additionalProperties } - class Serializer : BaseSerializer(Event::class) { - - override fun serialize( - value: Event, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.insertExperimentEventReplace != null -> - generator.writeObject(value.insertExperimentEventReplace) - value.insertExperimentEventMerge != null -> - generator.writeObject(value.insertExperimentEventMerge) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Event") - } - } + private val hashCode: Int by lazy { Objects.hash(events, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Body{events=$events, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is ExperimentInsertParams && + experimentId == other.experimentId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(experimentId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ExperimentInsertParams{experimentId=$experimentId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPage.kt index 4050f884..83d109f9 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPage.kt @@ -2,176 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.ExperimentService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see ExperimentService.list */ class ExperimentListPage private constructor( - private val experimentsService: ExperimentService, + private val service: ExperimentService, private val params: ExperimentListParams, - private val response: Response, -) { + private val response: ExperimentListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [ExperimentListPageResponse], but gracefully handles missing data. + * + * @see ExperimentListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExperimentListPage && - this.experimentsService == other.experimentsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - experimentsService, - params, - response, - ) - } - - override fun toString() = - "ExperimentListPage{experimentsService=$experimentsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ExperimentListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ExperimentListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ExperimentListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ExperimentListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): ExperimentListPage? { - return getNextPageParams()?.let { experimentsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - experimentsService: ExperimentService, - params: ExperimentListParams, - response: Response - ) = - ExperimentListPage( - experimentsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): ExperimentListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ExperimentListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ExperimentListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ExperimentListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ExperimentListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ExperimentService? = null + private var params: ExperimentListParams? = null + private var response: ExperimentListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(experimentListPage: ExperimentListPage) = apply { + service = experimentListPage.service + params = experimentListPage.params + response = experimentListPage.response } - override fun toString() = - "ExperimentListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ExperimentService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ExperimentListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ExperimentListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ExperimentListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExperimentListPage = + ExperimentListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ExperimentListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ExperimentListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ExperimentListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPageAsync.kt index a7487eca..5855390c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPageAsync.kt @@ -2,178 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.ExperimentServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see ExperimentServiceAsync.list */ class ExperimentListPageAsync private constructor( - private val experimentsService: ExperimentServiceAsync, + private val service: ExperimentServiceAsync, private val params: ExperimentListParams, - private val response: Response, -) { + private val response: ExperimentListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [ExperimentListPageResponse], but gracefully handles missing data. + * + * @see ExperimentListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExperimentListPageAsync && - this.experimentsService == other.experimentsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - experimentsService, - params, - response, - ) - } - - override fun toString() = - "ExperimentListPageAsync{experimentsService=$experimentsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ExperimentListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ExperimentListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ExperimentListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ExperimentListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): ExperimentListPageAsync? { - return getNextPageParams()?.let { experimentsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - experimentsService: ExperimentServiceAsync, - params: ExperimentListParams, - response: Response - ) = - ExperimentListPageAsync( - experimentsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): ExperimentListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ExperimentListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ExperimentListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ExperimentListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ExperimentListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ExperimentServiceAsync? = null + private var params: ExperimentListParams? = null + private var response: ExperimentListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(experimentListPageAsync: ExperimentListPageAsync) = apply { + service = experimentListPageAsync.service + params = experimentListPageAsync.params + response = experimentListPageAsync.response } - override fun toString() = - "ExperimentListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ExperimentServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ExperimentListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ExperimentListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ExperimentListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExperimentListPageAsync = + ExperimentListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ExperimentListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ExperimentListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ExperimentListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPageResponse.kt new file mode 100644 index 00000000..aa32d1f2 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 ExperimentListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of experiment objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [ExperimentListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ExperimentListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(experimentListPageResponse: ExperimentListPageResponse) = apply { + objects = experimentListPageResponse.objects.map { it.toMutableList() } + additionalProperties = experimentListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of experiment objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Experiment] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Experiment) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [ExperimentListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExperimentListPageResponse = + ExperimentListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ExperimentListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExperimentListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ExperimentListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListParams.kt index 5817844c..a977c260 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all experiments. The experiments are sorted by creation date, with the most + * recently-created experiments coming first + */ class ExperimentListParams -constructor( +private constructor( private val endingBefore: String?, private val experimentName: String?, private val ids: Ids?, @@ -29,91 +23,67 @@ constructor( private val projectId: String?, private val projectName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** Name of the experiment to search for */ fun experimentName(): String? = experimentName + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Project id */ fun projectId(): String? = projectId + /** Name of the project to search for */ fun projectName(): String? = projectName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.experimentName?.let { params.put("experiment_name", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.projectId?.let { params.put("project_id", listOf(it.toString())) } - this.projectName?.let { params.put("project_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExperimentListParams && - this.endingBefore == other.endingBefore && - this.experimentName == other.experimentName && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.projectId == other.projectId && - this.projectName == other.projectName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - experimentName, - ids, - limit, - orgName, - projectId, - projectName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "ExperimentListParams{endingBefore=$endingBefore, experimentName=$experimentName, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ExperimentListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ExperimentListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ExperimentListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var experimentName: String? = null @@ -123,20 +93,20 @@ constructor( private var projectId: String? = null private var projectName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(experimentListParams: ExperimentListParams) = apply { - this.endingBefore = experimentListParams.endingBefore - this.experimentName = experimentListParams.experimentName - this.ids = experimentListParams.ids - this.limit = experimentListParams.limit - this.orgName = experimentListParams.orgName - this.projectId = experimentListParams.projectId - this.projectName = experimentListParams.projectName - this.startingAfter = experimentListParams.startingAfter - additionalQueryParams(experimentListParams.additionalQueryParams) - additionalHeaders(experimentListParams.additionalHeaders) + endingBefore = experimentListParams.endingBefore + experimentName = experimentListParams.experimentName + ids = experimentListParams.ids + limit = experimentListParams.limit + orgName = experimentListParams.orgName + projectId = experimentListParams.projectId + projectName = experimentListParams.projectName + startingAfter = experimentListParams.startingAfter + additionalHeaders = experimentListParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentListParams.additionalQueryParams.toBuilder() } /** @@ -146,40 +116,41 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** Name of the experiment to search for */ - fun experimentName(experimentName: String) = apply { this.experimentName = experimentName } + fun experimentName(experimentName: String?) = apply { this.experimentName = experimentName } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String?) = apply { this.projectId = projectId } /** Name of the project to search for */ - fun projectName(projectName: String) = apply { this.projectName = projectName } + fun projectName(projectName: String?) = apply { this.projectName = projectName } /** * Pagination cursor id. @@ -188,48 +159,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ExperimentListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ExperimentListParams = ExperimentListParams( endingBefore, @@ -240,22 +274,48 @@ constructor( projectId, projectName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + experimentName?.let { put("experiment_name", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + projectId?.let { put("project_id", it) } + projectName?.let { put("project_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -268,93 +328,78 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is ExperimentListParams && + endingBefore == other.endingBefore && + experimentName == other.experimentName && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + projectId == other.projectId && + projectName == other.projectName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + experimentName, + ids, + limit, + orgName, + projectId, + projectName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ExperimentListParams{endingBefore=$endingBefore, experimentName=$experimentName, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParams.kt index 77220735..5547f1ea 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParams.kt @@ -2,125 +2,189 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get an experiment object by its id */ class ExperimentRetrieveParams -constructor( - private val experimentId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val experimentId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun experimentId(): String = experimentId + /** Experiment id */ + fun experimentId(): String? = experimentId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ExperimentRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ExperimentRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ExperimentRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var experimentId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(experimentRetrieveParams: ExperimentRetrieveParams) = apply { + experimentId = experimentRetrieveParams.experimentId + additionalHeaders = experimentRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentRetrieveParams.additionalQueryParams.toBuilder() } - return other is ExperimentRetrieveParams && - this.experimentId == other.experimentId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Experiment id */ + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } - override fun hashCode(): Int { - return Objects.hash( - experimentId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "ExperimentRetrieveParams{experimentId=$experimentId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var experimentId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(experimentRetrieveParams: ExperimentRetrieveParams) = apply { - this.experimentId = experimentRetrieveParams.experimentId - additionalQueryParams(experimentRetrieveParams.additionalQueryParams) - additionalHeaders(experimentRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ExperimentRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ExperimentRetrieveParams = ExperimentRetrieveParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + experimentId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + 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 ExperimentRetrieveParams && + experimentId == other.experimentId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(experimentId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ExperimentRetrieveParams{experimentId=$experimentId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParams.kt index 7c299139..ec4d03b9 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParams.kt @@ -2,101 +2,74 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Summarize experiment */ class ExperimentSummarizeParams -constructor( - private val experimentId: String, +private constructor( + private val experimentId: String?, private val comparisonExperimentId: String?, private val summarizeScores: Boolean?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - - fun experimentId(): String = experimentId - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Experiment id */ + fun experimentId(): String? = experimentId + + /** + * The experiment to compare against, if summarizing scores and metrics. If omitted, will fall + * back to the `base_exp_id` stored in the experiment metadata, and then to the most recent + * experiment run in the same project. Must pass `summarize_scores=true` for this id to be used + */ fun comparisonExperimentId(): String? = comparisonExperimentId + /** + * Whether to summarize the scores and metrics. If false (or omitted), only the metadata will be + * returned. + */ fun summarizeScores(): Boolean? = summarizeScores - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.comparisonExperimentId?.let { - params.put("comparison_experiment_id", listOf(it.toString())) - } - this.summarizeScores?.let { params.put("summarize_scores", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" - } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExperimentSummarizeParams && - this.experimentId == other.experimentId && - this.comparisonExperimentId == other.comparisonExperimentId && - this.summarizeScores == other.summarizeScores && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - experimentId, - comparisonExperimentId, - summarizeScores, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "ExperimentSummarizeParams{experimentId=$experimentId, comparisonExperimentId=$comparisonExperimentId, summarizeScores=$summarizeScores, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ExperimentSummarizeParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [ExperimentSummarizeParams]. + */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ExperimentSummarizeParams]. */ + class Builder internal constructor() { private var experimentId: String? = null private var comparisonExperimentId: String? = null private var summarizeScores: Boolean? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(experimentSummarizeParams: ExperimentSummarizeParams) = apply { - this.experimentId = experimentSummarizeParams.experimentId - this.comparisonExperimentId = experimentSummarizeParams.comparisonExperimentId - this.summarizeScores = experimentSummarizeParams.summarizeScores - additionalQueryParams(experimentSummarizeParams.additionalQueryParams) - additionalHeaders(experimentSummarizeParams.additionalHeaders) + experimentId = experimentSummarizeParams.experimentId + comparisonExperimentId = experimentSummarizeParams.comparisonExperimentId + summarizeScores = experimentSummarizeParams.summarizeScores + additionalHeaders = experimentSummarizeParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentSummarizeParams.additionalQueryParams.toBuilder() } /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } /** * The experiment to compare against, if summarizing scores and metrics. If omitted, will @@ -104,7 +77,7 @@ constructor( * recent experiment run in the same project. Must pass `summarize_scores=true` for this id * to be used */ - fun comparisonExperimentId(comparisonExperimentId: String) = apply { + fun comparisonExperimentId(comparisonExperimentId: String?) = apply { this.comparisonExperimentId = comparisonExperimentId } @@ -112,57 +85,169 @@ constructor( * Whether to summarize the scores and metrics. If false (or omitted), only the metadata * will be returned. */ - fun summarizeScores(summarizeScores: Boolean) = apply { + fun summarizeScores(summarizeScores: Boolean?) = apply { this.summarizeScores = summarizeScores } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + /** + * Alias for [Builder.summarizeScores]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun summarizeScores(summarizeScores: Boolean) = summarizeScores(summarizeScores as Boolean?) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ExperimentSummarizeParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ExperimentSummarizeParams = ExperimentSummarizeParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, + experimentId, comparisonExperimentId, summarizeScores, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + comparisonExperimentId?.let { put("comparison_experiment_id", it) } + summarizeScores?.let { put("summarize_scores", it.toString()) } + putAll(additionalQueryParams) + } + .build() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExperimentSummarizeParams && + experimentId == other.experimentId && + comparisonExperimentId == other.comparisonExperimentId && + summarizeScores == other.summarizeScores && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + experimentId, + comparisonExperimentId, + summarizeScores, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ExperimentSummarizeParams{experimentId=$experimentId, comparisonExperimentId=$comparisonExperimentId, summarizeScores=$summarizeScores, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentUpdateParams.kt index 96ff5d88..8c4476e8 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ExperimentUpdateParams.kt @@ -3,296 +3,500 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update an experiment object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ class ExperimentUpdateParams -constructor( - private val experimentId: String, - private val baseExpId: String?, - private val datasetId: String?, - private val datasetVersion: String?, - private val description: String?, - private val metadata: Metadata?, - private val name: String?, - private val public_: Boolean?, - private val repoInfo: RepoInfo?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val experimentId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Experiment id */ + fun experimentId(): String? = experimentId + + /** + * Id of default base experiment to compare against when viewing this experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baseExpId(): String? = body.baseExpId() + + /** + * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun datasetId(): String? = body.datasetId() + + /** + * Version number of the linked dataset the experiment was run against. This can be used to + * reproduce the experiment after the dataset has been modified. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun datasetVersion(): String? = body.datasetVersion() + + /** + * Textual description of the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * User-controlled metadata about the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * Name of the experiment. Within a project, experiment names are unique + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * Whether or not the experiment is public. Public experiments can be viewed by anybody inside + * or outside the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun public_(): Boolean? = body.public_() + + /** + * Metadata about the state of the repo when the experiment was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun repoInfo(): RepoInfo? = body.repoInfo() + + /** + * Returns the raw JSON value of [baseExpId]. + * + * Unlike [baseExpId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _baseExpId(): JsonField = body._baseExpId() + + /** + * Returns the raw JSON value of [datasetId]. + * + * Unlike [datasetId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _datasetId(): JsonField = body._datasetId() + + /** + * Returns the raw JSON value of [datasetVersion]. + * + * Unlike [datasetVersion], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _datasetVersion(): JsonField = body._datasetVersion() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [public_]. + * + * Unlike [public_], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _public_(): JsonField = body._public_() + + /** + * Returns the raw JSON value of [repoInfo]. + * + * Unlike [repoInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _repoInfo(): JsonField = body._repoInfo() + + 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 experimentId(): String = experimentId - - fun baseExpId(): String? = baseExpId - - fun datasetId(): String? = datasetId - - fun datasetVersion(): String? = datasetVersion - - fun description(): String? = description - - fun metadata(): Metadata? = metadata - - fun name(): String? = name + fun toBuilder() = Builder().from(this) - fun public_(): Boolean? = public_ + companion object { - fun repoInfo(): RepoInfo? = repoInfo + fun none(): ExperimentUpdateParams = builder().build() - internal fun getBody(): ExperimentUpdateBody { - return ExperimentUpdateBody( - baseExpId, - datasetId, - datasetVersion, - description, - metadata, - name, - public_, - repoInfo, - additionalBodyProperties, - ) + /** Returns a mutable builder for constructing an instance of [ExperimentUpdateParams]. */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ExperimentUpdateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var experimentId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> experimentId - else -> "" + internal fun from(experimentUpdateParams: ExperimentUpdateParams) = apply { + experimentId = experimentUpdateParams.experimentId + body = experimentUpdateParams.body.toBuilder() + additionalHeaders = experimentUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = experimentUpdateParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ExperimentUpdateBody.Builder::class) - @NoAutoDetect - class ExperimentUpdateBody - internal constructor( - private val baseExpId: String?, - private val datasetId: String?, - private val datasetVersion: String?, - private val description: String?, - private val metadata: Metadata?, - private val name: String?, - private val public_: Boolean?, - private val repoInfo: RepoInfo?, - private val additionalProperties: Map, - ) { + /** Experiment id */ + fun experimentId(experimentId: String?) = apply { this.experimentId = experimentId } - private var hashCode: Int = 0 + /** + * 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: + * - [baseExpId] + * - [datasetId] + * - [datasetVersion] + * - [description] + * - [metadata] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Id of default base experiment to compare against when viewing this experiment */ - @JsonProperty("base_exp_id") fun baseExpId(): String? = baseExpId + fun baseExpId(baseExpId: String?) = apply { body.baseExpId(baseExpId) } + + /** + * Sets [Builder.baseExpId] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExpId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun baseExpId(baseExpId: JsonField) = apply { body.baseExpId(baseExpId) } /** * Identifier of the linked dataset, or null if the experiment is not linked to a dataset */ - @JsonProperty("dataset_id") fun datasetId(): String? = datasetId + fun datasetId(datasetId: String?) = apply { body.datasetId(datasetId) } + + /** + * Sets [Builder.datasetId] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun datasetId(datasetId: JsonField) = apply { body.datasetId(datasetId) } /** * Version number of the linked dataset the experiment was run against. This can be used to * reproduce the experiment after the dataset has been modified. */ - @JsonProperty("dataset_version") fun datasetVersion(): String? = datasetVersion + fun datasetVersion(datasetVersion: String?) = apply { body.datasetVersion(datasetVersion) } + + /** + * Sets [Builder.datasetVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetVersion] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun datasetVersion(datasetVersion: JsonField) = apply { + body.datasetVersion(datasetVersion) + } /** Textual description of the experiment */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** User-controlled metadata about the experiment */ - @JsonProperty("metadata") fun metadata(): Metadata? = metadata + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } /** Name of the experiment. Within a project, experiment names are unique */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** * Whether or not the experiment is public. Public experiments can be viewed by anybody * inside or outside the organization */ - @JsonProperty("public") fun public_(): Boolean? = public_ + fun public_(public_: Boolean?) = apply { body.public_(public_) } + + /** + * Alias for [Builder.public_]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun public_(public_: Boolean) = public_(public_ as Boolean?) + + /** + * Sets [Builder.public_] to an arbitrary JSON value. + * + * You should usually call [Builder.public_] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun public_(public_: JsonField) = apply { body.public_(public_) } /** Metadata about the state of the repo when the experiment was created */ - @JsonProperty("repo_info") fun repoInfo(): RepoInfo? = repoInfo + fun repoInfo(repoInfo: RepoInfo?) = apply { body.repoInfo(repoInfo) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.repoInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.repoInfo] with a well-typed [RepoInfo] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun repoInfo(repoInfo: JsonField) = apply { body.repoInfo(repoInfo) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is ExperimentUpdateBody && - this.baseExpId == other.baseExpId && - this.datasetId == other.datasetId && - this.datasetVersion == other.datasetVersion && - this.description == other.description && - this.metadata == other.metadata && - this.name == other.name && - this.public_ == other.public_ && - this.repoInfo == other.repoInfo && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - baseExpId, - datasetId, - datasetVersion, - description, - metadata, - name, - public_, - repoInfo, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "ExperimentUpdateBody{baseExpId=$baseExpId, datasetId=$datasetId, datasetVersion=$datasetVersion, description=$description, metadata=$metadata, name=$name, public_=$public_, repoInfo=$repoInfo, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var baseExpId: String? = null - private var datasetId: String? = null - private var datasetVersion: String? = null - private var description: String? = null - private var metadata: Metadata? = null - private var name: String? = null - private var public_: Boolean? = null - private var repoInfo: RepoInfo? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(experimentUpdateBody: ExperimentUpdateBody) = apply { - this.baseExpId = experimentUpdateBody.baseExpId - this.datasetId = experimentUpdateBody.datasetId - this.datasetVersion = experimentUpdateBody.datasetVersion - this.description = experimentUpdateBody.description - this.metadata = experimentUpdateBody.metadata - this.name = experimentUpdateBody.name - this.public_ = experimentUpdateBody.public_ - this.repoInfo = experimentUpdateBody.repoInfo - additionalProperties(experimentUpdateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Id of default base experiment to compare against when viewing this experiment */ - @JsonProperty("base_exp_id") - fun baseExpId(baseExpId: String) = apply { this.baseExpId = baseExpId } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** - * Identifier of the linked dataset, or null if the experiment is not linked to a - * dataset - */ - @JsonProperty("dataset_id") - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * Version number of the linked dataset the experiment was run against. This can be used - * to reproduce the experiment after the dataset has been modified. - */ - @JsonProperty("dataset_version") - fun datasetVersion(datasetVersion: String) = apply { - this.datasetVersion = datasetVersion - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Textual description of the experiment */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** User-controlled metadata about the experiment */ - @JsonProperty("metadata") - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** Name of the experiment. Within a project, experiment names are unique */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** - * Whether or not the experiment is public. Public experiments can be viewed by anybody - * inside or outside the organization - */ - @JsonProperty("public") fun public_(public_: Boolean) = apply { this.public_ = public_ } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - /** Metadata about the state of the repo when the experiment was created */ - @JsonProperty("repo_info") - fun repoInfo(repoInfo: RepoInfo) = apply { this.repoInfo = repoInfo } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun build(): ExperimentUpdateBody = - ExperimentUpdateBody( - baseExpId, - datasetId, - datasetVersion, - description, - metadata, - name, - public_, - repoInfo, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ExperimentUpdateParams && - this.experimentId == other.experimentId && - this.baseExpId == other.baseExpId && - this.datasetId == other.datasetId && - this.datasetVersion == other.datasetVersion && - this.description == other.description && - this.metadata == other.metadata && - this.name == other.name && - this.public_ == other.public_ && - this.repoInfo == other.repoInfo && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ExperimentUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ExperimentUpdateParams = + ExperimentUpdateParams( + experimentId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - experimentId, + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> experimentId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val baseExpId: JsonField, + private val datasetId: JsonField, + private val datasetVersion: JsonField, + private val description: JsonField, + private val metadata: JsonField, + private val name: JsonField, + private val public_: JsonField, + private val repoInfo: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("base_exp_id") + @ExcludeMissing + baseExpId: JsonField = JsonMissing.of(), + @JsonProperty("dataset_id") + @ExcludeMissing + datasetId: JsonField = JsonMissing.of(), + @JsonProperty("dataset_version") + @ExcludeMissing + datasetVersion: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("public") @ExcludeMissing public_: JsonField = JsonMissing.of(), + @JsonProperty("repo_info") + @ExcludeMissing + repoInfo: JsonField = JsonMissing.of(), + ) : this( baseExpId, datasetId, datasetVersion, @@ -301,145 +505,395 @@ constructor( name, public_, repoInfo, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - override fun toString() = - "ExperimentUpdateParams{experimentId=$experimentId, baseExpId=$baseExpId, datasetId=$datasetId, datasetVersion=$datasetVersion, description=$description, metadata=$metadata, name=$name, public_=$public_, repoInfo=$repoInfo, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + /** + * Id of default base experiment to compare against when viewing this experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun baseExpId(): String? = baseExpId.getNullable("base_exp_id") - fun toBuilder() = Builder().from(this) + /** + * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun datasetId(): String? = datasetId.getNullable("dataset_id") - companion object { + /** + * Version number of the linked dataset the experiment was run against. This can be used to + * reproduce the experiment after the dataset has been modified. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun datasetVersion(): String? = datasetVersion.getNullable("dataset_version") - fun builder() = Builder() - } + /** + * Textual description of the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - @NoAutoDetect - class Builder { + /** + * User-controlled metadata about the experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") - private var experimentId: String? = null - private var baseExpId: String? = null - private var datasetId: String? = null - private var datasetVersion: String? = null - private var description: String? = null - private var metadata: Metadata? = null - private var name: String? = null - private var public_: Boolean? = null - private var repoInfo: RepoInfo? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + /** + * Name of the experiment. Within a project, experiment names are unique + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") - internal fun from(experimentUpdateParams: ExperimentUpdateParams) = apply { - this.experimentId = experimentUpdateParams.experimentId - this.baseExpId = experimentUpdateParams.baseExpId - this.datasetId = experimentUpdateParams.datasetId - this.datasetVersion = experimentUpdateParams.datasetVersion - this.description = experimentUpdateParams.description - this.metadata = experimentUpdateParams.metadata - this.name = experimentUpdateParams.name - this.public_ = experimentUpdateParams.public_ - this.repoInfo = experimentUpdateParams.repoInfo - additionalQueryParams(experimentUpdateParams.additionalQueryParams) - additionalHeaders(experimentUpdateParams.additionalHeaders) - additionalBodyProperties(experimentUpdateParams.additionalBodyProperties) - } + /** + * Whether or not the experiment is public. Public experiments can be viewed by anybody + * inside or outside the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun public_(): Boolean? = public_.getNullable("public") - /** Experiment id */ - fun experimentId(experimentId: String) = apply { this.experimentId = experimentId } + /** + * Metadata about the state of the repo when the experiment was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun repoInfo(): RepoInfo? = repoInfo.getNullable("repo_info") - /** Id of default base experiment to compare against when viewing this experiment */ - fun baseExpId(baseExpId: String) = apply { this.baseExpId = baseExpId } + /** + * Returns the raw JSON value of [baseExpId]. + * + * Unlike [baseExpId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("base_exp_id") @ExcludeMissing fun _baseExpId(): JsonField = baseExpId /** - * Identifier of the linked dataset, or null if the experiment is not linked to a dataset + * Returns the raw JSON value of [datasetId]. + * + * Unlike [datasetId], this method doesn't throw if the JSON field has an unexpected type. */ - fun datasetId(datasetId: String) = apply { this.datasetId = datasetId } + @JsonProperty("dataset_id") @ExcludeMissing fun _datasetId(): JsonField = datasetId /** - * Version number of the linked dataset the experiment was run against. This can be used to - * reproduce the experiment after the dataset has been modified. + * Returns the raw JSON value of [datasetVersion]. + * + * Unlike [datasetVersion], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun datasetVersion(datasetVersion: String) = apply { this.datasetVersion = datasetVersion } + @JsonProperty("dataset_version") + @ExcludeMissing + fun _datasetVersion(): JsonField = datasetVersion - /** Textual description of the experiment */ - fun description(description: String) = apply { this.description = description } + /** + * 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 - /** User-controlled metadata about the experiment */ - fun metadata(metadata: Metadata) = apply { this.metadata = metadata } + /** + * 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 - /** Name of the experiment. Within a project, experiment names are unique */ - fun name(name: String) = apply { this.name = name } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Whether or not the experiment is public. Public experiments can be viewed by anybody - * inside or outside the organization + * Returns the raw JSON value of [public_]. + * + * Unlike [public_], this method doesn't throw if the JSON field has an unexpected type. */ - fun public_(public_: Boolean) = apply { this.public_ = public_ } + @JsonProperty("public") @ExcludeMissing fun _public_(): JsonField = public_ - /** Metadata about the state of the repo when the experiment was created */ - fun repoInfo(repoInfo: RepoInfo) = apply { this.repoInfo = repoInfo } + /** + * Returns the raw JSON value of [repoInfo]. + * + * Unlike [repoInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("repo_info") @ExcludeMissing fun _repoInfo(): JsonField = repoInfo - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + companion object { - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var baseExpId: JsonField = JsonMissing.of() + private var datasetId: JsonField = JsonMissing.of() + private var datasetVersion: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var public_: JsonField = JsonMissing.of() + private var repoInfo: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + internal fun from(body: Body) = apply { + baseExpId = body.baseExpId + datasetId = body.datasetId + datasetVersion = body.datasetVersion + description = body.description + metadata = body.metadata + name = body.name + public_ = body.public_ + repoInfo = body.repoInfo + additionalProperties = body.additionalProperties.toMutableMap() + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** Id of default base experiment to compare against when viewing this experiment */ + fun baseExpId(baseExpId: String?) = baseExpId(JsonField.ofNullable(baseExpId)) - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** + * Sets [Builder.baseExpId] to an arbitrary JSON value. + * + * You should usually call [Builder.baseExpId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun baseExpId(baseExpId: JsonField) = apply { this.baseExpId = baseExpId } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** + * Identifier of the linked dataset, or null if the experiment is not linked to a + * dataset + */ + fun datasetId(datasetId: String?) = datasetId(JsonField.ofNullable(datasetId)) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Sets [Builder.datasetId] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun datasetId(datasetId: JsonField) = apply { this.datasetId = datasetId } + + /** + * Version number of the linked dataset the experiment was run against. This can be used + * to reproduce the experiment after the dataset has been modified. + */ + fun datasetVersion(datasetVersion: String?) = + datasetVersion(JsonField.ofNullable(datasetVersion)) + + /** + * Sets [Builder.datasetVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetVersion] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun datasetVersion(datasetVersion: JsonField) = apply { + this.datasetVersion = datasetVersion + } + + /** Textual description of the experiment */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** User-controlled metadata about the experiment */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + + /** Name of the experiment. Within a project, experiment names are unique */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Whether or not the experiment is public. Public experiments can be viewed by anybody + * inside or outside the organization + */ + fun public_(public_: Boolean?) = public_(JsonField.ofNullable(public_)) + + /** + * Alias for [Builder.public_]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun public_(public_: Boolean) = public_(public_ as Boolean?) + + /** + * Sets [Builder.public_] to an arbitrary JSON value. + * + * You should usually call [Builder.public_] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun public_(public_: JsonField) = apply { this.public_ = public_ } + + /** Metadata about the state of the repo when the experiment was created */ + fun repoInfo(repoInfo: RepoInfo?) = repoInfo(JsonField.ofNullable(repoInfo)) + + /** + * Sets [Builder.repoInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.repoInfo] with a well-typed [RepoInfo] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun repoInfo(repoInfo: JsonField) = apply { this.repoInfo = repoInfo } + + 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( + baseExpId, + datasetId, + datasetVersion, + description, + metadata, + name, + public_, + repoInfo, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + baseExpId() + datasetId() + datasetVersion() + description() + metadata()?.validate() + name() + public_() + repoInfo()?.validate() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ExperimentUpdateParams = - ExperimentUpdateParams( - checkNotNull(experimentId) { "`experimentId` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (baseExpId.asKnown() == null) 0 else 1) + + (if (datasetId.asKnown() == null) 0 else 1) + + (if (datasetVersion.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (if (public_.asKnown() == null) 0 else 1) + + (repoInfo.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + baseExpId == other.baseExpId && + datasetId == other.datasetId && + datasetVersion == other.datasetVersion && + description == other.description && + metadata == other.metadata && + name == other.name && + public_ == other.public_ && + repoInfo == other.repoInfo && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( baseExpId, datasetId, datasetVersion, @@ -448,73 +902,129 @@ constructor( name, public_, repoInfo, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{baseExpId=$baseExpId, datasetId=$datasetId, datasetVersion=$datasetVersion, description=$description, metadata=$metadata, name=$name, public_=$public_, repoInfo=$repoInfo, additionalProperties=$additionalProperties}" } /** User-controlled metadata about the experiment */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is ExperimentUpdateParams && + experimentId == other.experimentId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(experimentId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ExperimentUpdateParams{experimentId=$experimentId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackDatasetItem.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackDatasetItem.kt index c3c8484e..b25212fd 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackDatasetItem.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackDatasetItem.kt @@ -7,132 +7,157 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FeedbackDatasetItem.Builder::class) -@NoAutoDetect class FeedbackDatasetItem +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val comment: JsonField, private val metadata: JsonField, private val source: JsonField, - private val additionalProperties: Map, + private val tags: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("comment") @ExcludeMissing comment: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("source") @ExcludeMissing source: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this(id, comment, metadata, source, tags, mutableMapOf()) /** * The id of the dataset event to log feedback for. This is the row `id` returned by `POST * /v1/dataset/{dataset_id}/insert` + * + * @throws BraintrustInvalidDataException 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") - /** An optional comment string to log about the dataset event */ + /** + * An optional comment string to log about the dataset event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun comment(): String? = comment.getNullable("comment") /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * here and access it in the Braintrust UI. Note, this metadata does not correspond to the main + * event itself, but rather the audit log attached to the event. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ + /** + * The source of the feedback. Must be one of "external" (default), "app", or "api" + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun source(): Source? = source.getNullable("source") /** - * The id of the dataset event to log feedback for. This is the row `id` returned by `POST - * /v1/dataset/{dataset_id}/insert` + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** An optional comment string to log about the dataset event */ - @JsonProperty("comment") @ExcludeMissing fun _comment() = comment + fun tags(): List? = tags.getNullable("tags") /** - * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - @JsonProperty("source") @ExcludeMissing fun _source() = source + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Returns the raw JSON value of [comment]. + * + * Unlike [comment], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("comment") @ExcludeMissing fun _comment(): JsonField = comment - fun validate(): FeedbackDatasetItem = apply { - if (!validated) { - id() - comment() - metadata()?.validate() - source() - validated = true - } - } + /** + * 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 - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [source]. + * + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - return other is FeedbackDatasetItem && - this.id == other.id && - this.comment == other.comment && - this.metadata == other.metadata && - this.source == other.source && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - comment, - metadata, - source, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "FeedbackDatasetItem{id=$id, comment=$comment, metadata=$metadata, source=$source, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [FeedbackDatasetItem]. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FeedbackDatasetItem]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() + private var id: JsonField? = null private var comment: JsonField = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() private var source: JsonField = JsonMissing.of() + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(feedbackDatasetItem: FeedbackDatasetItem) = apply { - this.id = feedbackDatasetItem.id - this.comment = feedbackDatasetItem.comment - this.metadata = feedbackDatasetItem.metadata - this.source = feedbackDatasetItem.source - additionalProperties(feedbackDatasetItem.additionalProperties) + id = feedbackDatasetItem.id + comment = feedbackDatasetItem.comment + metadata = feedbackDatasetItem.metadata + source = feedbackDatasetItem.source + tags = feedbackDatasetItem.tags.map { it.toMutableList() } + additionalProperties = feedbackDatasetItem.additionalProperties.toMutableMap() } /** @@ -142,184 +167,308 @@ private constructor( fun id(id: String) = id(JsonField.of(id)) /** - * The id of the dataset event to log feedback for. This is the row `id` returned by `POST - * /v1/dataset/{dataset_id}/insert` + * 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. */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } + fun id(id: JsonField) = apply { this.id = id } /** An optional comment string to log about the dataset event */ - fun comment(comment: String) = comment(JsonField.of(comment)) + fun comment(comment: String?) = comment(JsonField.ofNullable(comment)) - /** An optional comment string to log about the dataset event */ - @JsonProperty("comment") - @ExcludeMissing + /** + * Sets [Builder.comment] to an arbitrary JSON value. + * + * You should usually call [Builder.comment] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun comment(comment: JsonField) = apply { this.comment = comment } /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can - * log it here and access it in the Braintrust UI. + * log it here and access it in the Braintrust UI. Note, this metadata does not correspond + * to the main event itself, but rather the audit log attached to the event. */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) /** - * A dictionary with additional data about the feedback. If you have a `user_id`, you can - * log it here and access it in the Braintrust UI. + * 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. */ - @JsonProperty("metadata") - @ExcludeMissing fun metadata(metadata: JsonField) = apply { this.metadata = metadata } /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - fun source(source: Source) = source(JsonField.of(source)) + fun source(source: Source?) = source(JsonField.ofNullable(source)) - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - @JsonProperty("source") - @ExcludeMissing + /** + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [Source] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun source(source: JsonField) = apply { this.source = source } + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FeedbackDatasetItem]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FeedbackDatasetItem = FeedbackDatasetItem( - id, + checkRequired("id", id), comment, metadata, source, - additionalProperties.toUnmodifiable(), + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): FeedbackDatasetItem = apply { + if (validated) { + return@apply + } + + id() + comment() + metadata()?.validate() + source()?.validate() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (comment.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (source.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * here and access it in the Braintrust UI. Note, this metadata does not correspond to the main + * event itself, but rather the audit log attached to the event. */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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()) } - } - class Source - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Source && this.value == other.value + return other is Metadata && additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + } + + /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ + class Source @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 { - val APP = Source(JsonField.of("app")) + val APP = of("app") - val API = Source(JsonField.of("api")) + val API = of("api") - val EXTERNAL = Source(JsonField.of("external")) + val EXTERNAL = of("external") fun of(value: String) = Source(JsonField.of(value)) } + /** An enum containing [Source]'s known values. */ enum class Known { APP, API, EXTERNAL, } + /** + * An enum containing [Source]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Source] 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 { APP, API, EXTERNAL, + /** An enum member indicating that [Source] 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) { APP -> Value.APP @@ -328,6 +477,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { APP -> Known.APP @@ -336,6 +494,78 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown Source: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Source = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Source && 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 FeedbackDatasetItem && + id == other.id && + comment == other.comment && + metadata == other.metadata && + source == other.source && + tags == other.tags && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { + Objects.hash(id, comment, metadata, source, tags, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FeedbackDatasetItem{id=$id, comment=$comment, metadata=$metadata, source=$source, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackExperimentItem.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackExperimentItem.kt index 46b51169..c9d1bd6a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackExperimentItem.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackExperimentItem.kt @@ -7,168 +7,187 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FeedbackExperimentItem.Builder::class) -@NoAutoDetect class FeedbackExperimentItem +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val scores: JsonField, - private val expected: JsonValue, private val comment: JsonField, + private val expected: JsonValue, private val metadata: JsonField, + private val scores: JsonField, private val source: JsonField, - private val additionalProperties: Map, + private val tags: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("comment") @ExcludeMissing comment: JsonField = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + @JsonProperty("source") @ExcludeMissing source: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this(id, comment, expected, metadata, scores, source, tags, mutableMapOf()) /** * The id of the experiment event to log feedback for. This is the row `id` returned by `POST * /v1/experiment/{experiment_id}/insert` + * + * @throws BraintrustInvalidDataException 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") /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the - * existing scores for the experiment event + * An optional comment string to log about the experiment event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun scores(): Scores? = scores.getNullable("scores") + fun comment(): String? = comment.getNullable("comment") /** * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to * `output` to determine if your `output` value is correct or not */ - fun expected(): JsonValue = expected - - /** An optional comment string to log about the experiment event */ - fun comment(): String? = comment.getNullable("comment") + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * here and access it in the Braintrust UI. Note, this metadata does not correspond to the main + * event itself, but rather the audit log attached to the event. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - fun source(): Source? = source.getNullable("source") - - /** - * The id of the experiment event to log feedback for. This is the row `id` returned by `POST - * /v1/experiment/{experiment_id}/insert` - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - /** * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the * existing scores for the experiment event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores + fun scores(): Scores? = scores.getNullable("scores") /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not + * The source of the feedback. Must be one of "external" (default), "app", or "api" + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected + fun source(): Source? = source.getNullable("source") - /** An optional comment string to log about the experiment event */ - @JsonProperty("comment") @ExcludeMissing fun _comment() = comment + /** + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") /** - * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - @JsonProperty("source") @ExcludeMissing fun _source() = source + /** + * Returns the raw JSON value of [comment]. + * + * Unlike [comment], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("comment") @ExcludeMissing fun _comment(): JsonField = comment - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * 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 - fun validate(): FeedbackExperimentItem = apply { - if (!validated) { - id() - scores()?.validate() - expected() - comment() - metadata()?.validate() - source() - validated = true - } - } + /** + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [source]. + * + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - return other is FeedbackExperimentItem && - this.id == other.id && - this.scores == other.scores && - this.expected == other.expected && - this.comment == other.comment && - this.metadata == other.metadata && - this.source == other.source && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - scores, - expected, - comment, - metadata, - source, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "FeedbackExperimentItem{id=$id, scores=$scores, expected=$expected, comment=$comment, metadata=$metadata, source=$source, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [FeedbackExperimentItem]. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FeedbackExperimentItem]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() + private var id: JsonField? = null private var comment: JsonField = JsonMissing.of() + private var expected: JsonValue = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() + private var scores: JsonField = JsonMissing.of() private var source: JsonField = JsonMissing.of() + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(feedbackExperimentItem: FeedbackExperimentItem) = apply { - this.id = feedbackExperimentItem.id - this.scores = feedbackExperimentItem.scores - this.expected = feedbackExperimentItem.expected - this.comment = feedbackExperimentItem.comment - this.metadata = feedbackExperimentItem.metadata - this.source = feedbackExperimentItem.source - additionalProperties(feedbackExperimentItem.additionalProperties) + id = feedbackExperimentItem.id + comment = feedbackExperimentItem.comment + expected = feedbackExperimentItem.expected + metadata = feedbackExperimentItem.metadata + scores = feedbackExperimentItem.scores + source = feedbackExperimentItem.source + tags = feedbackExperimentItem.tags.map { it.toMutableList() } + additionalProperties = feedbackExperimentItem.additionalProperties.toMutableMap() } /** @@ -178,283 +197,433 @@ private constructor( fun id(id: String) = id(JsonField.of(id)) /** - * The id of the experiment event to log feedback for. This is the row `id` returned by - * `POST /v1/experiment/{experiment_id}/insert` + * 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. */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } + fun id(id: JsonField) = apply { this.id = id } - /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into - * the existing scores for the experiment event - */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) + /** An optional comment string to log about the experiment event */ + fun comment(comment: String?) = comment(JsonField.ofNullable(comment)) /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into - * the existing scores for the experiment event + * Sets [Builder.comment] to an arbitrary JSON value. + * + * You should usually call [Builder.comment] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } + fun comment(comment: JsonField) = apply { this.comment = comment } /** * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to * `output` to determine if your `output` value is correct or not */ - @JsonProperty("expected") - @ExcludeMissing fun expected(expected: JsonValue) = apply { this.expected = expected } - /** An optional comment string to log about the experiment event */ - fun comment(comment: String) = comment(JsonField.of(comment)) - - /** An optional comment string to log about the experiment event */ - @JsonProperty("comment") - @ExcludeMissing - fun comment(comment: JsonField) = apply { this.comment = comment } - /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can - * log it here and access it in the Braintrust UI. + * log it here and access it in the Braintrust UI. Note, this metadata does not correspond + * to the main event itself, but rather the audit log attached to the event. */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) /** - * A dictionary with additional data about the feedback. If you have a `user_id`, you can - * log it here and access it in the Braintrust UI. + * 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. */ - @JsonProperty("metadata") - @ExcludeMissing fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - fun source(source: Source) = source(JsonField.of(source)) + /** + * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into + * the existing scores for the experiment event + */ + fun scores(scores: Scores?) = scores(JsonField.ofNullable(scores)) + + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun scores(scores: JsonField) = apply { this.scores = scores } /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - @JsonProperty("source") - @ExcludeMissing + fun source(source: Source?) = source(JsonField.ofNullable(source)) + + /** + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [Source] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun source(source: JsonField) = apply { this.source = source } + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FeedbackExperimentItem]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FeedbackExperimentItem = FeedbackExperimentItem( - id, - scores, - expected, + checkRequired("id", id), comment, + expected, metadata, + scores, source, - additionalProperties.toUnmodifiable(), + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): FeedbackExperimentItem = apply { + if (validated) { + return@apply + } + + id() + comment() + metadata()?.validate() + scores()?.validate() + source()?.validate() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (comment.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (scores.asKnown()?.validity() ?: 0) + + (source.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * here and access it in the Braintrust UI. Note, this metadata does not correspond to the main + * event itself, but rather the audit log attached to the event. */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the - * existing scores for the experiment event - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { + 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 - private var hashCode: Int = 0 + fun validate(): Metadata = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): Scores = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Scores && this.additionalProperties == other.additionalProperties + return other is Metadata && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "Scores{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + } + + /** + * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the + * existing scores for the experiment event + */ + class Scores + @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 [Scores]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Scores]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) + additionalProperties = scores.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) } - } - class Source - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Scores = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Source && this.value == other.value + return other is Scores && additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = "Scores{additionalProperties=$additionalProperties}" + } + + /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ + class Source @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 { - val APP = Source(JsonField.of("app")) + val APP = of("app") - val API = Source(JsonField.of("api")) + val API = of("api") - val EXTERNAL = Source(JsonField.of("external")) + val EXTERNAL = of("external") fun of(value: String) = Source(JsonField.of(value)) } + /** An enum containing [Source]'s known values. */ enum class Known { APP, API, EXTERNAL, } + /** + * An enum containing [Source]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Source] 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 { APP, API, EXTERNAL, + /** An enum member indicating that [Source] 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) { APP -> Value.APP @@ -463,6 +632,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { APP -> Known.APP @@ -471,6 +649,80 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown Source: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Source = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Source && 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 FeedbackExperimentItem && + id == other.id && + comment == other.comment && + expected == other.expected && + metadata == other.metadata && + scores == other.scores && + source == other.source && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, comment, expected, metadata, scores, source, tags, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FeedbackExperimentItem{id=$id, comment=$comment, expected=$expected, metadata=$metadata, scores=$scores, source=$source, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItem.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItem.kt index f9d74e8f..887823ba 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItem.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItem.kt @@ -7,168 +7,187 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FeedbackProjectLogsItem.Builder::class) -@NoAutoDetect class FeedbackProjectLogsItem +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val scores: JsonField, - private val expected: JsonValue, private val comment: JsonField, + private val expected: JsonValue, private val metadata: JsonField, + private val scores: JsonField, private val source: JsonField, - private val additionalProperties: Map, + private val tags: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("comment") @ExcludeMissing comment: JsonField = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + @JsonProperty("source") @ExcludeMissing source: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this(id, comment, expected, metadata, scores, source, tags, mutableMapOf()) /** * The id of the project logs event to log feedback for. This is the row `id` returned by `POST * /v1/project_logs/{project_id}/insert` + * + * @throws BraintrustInvalidDataException 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") /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the - * existing scores for the project logs event + * An optional comment string to log about the project logs event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun scores(): Scores? = scores.getNullable("scores") + fun comment(): String? = comment.getNullable("comment") /** * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to * `output` to determine if your `output` value is correct or not */ - fun expected(): JsonValue = expected - - /** An optional comment string to log about the project logs event */ - fun comment(): String? = comment.getNullable("comment") + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * here and access it in the Braintrust UI. Note, this metadata does not correspond to the main + * event itself, but rather the audit log attached to the event. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - fun source(): Source? = source.getNullable("source") - - /** - * The id of the project logs event to log feedback for. This is the row `id` returned by `POST - * /v1/project_logs/{project_id}/insert` - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - /** * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the * existing scores for the project logs event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores + fun scores(): Scores? = scores.getNullable("scores") /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not + * The source of the feedback. Must be one of "external" (default), "app", or "api" + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected + fun source(): Source? = source.getNullable("source") - /** An optional comment string to log about the project logs event */ - @JsonProperty("comment") @ExcludeMissing fun _comment() = comment + /** + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") /** - * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - @JsonProperty("source") @ExcludeMissing fun _source() = source + /** + * Returns the raw JSON value of [comment]. + * + * Unlike [comment], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("comment") @ExcludeMissing fun _comment(): JsonField = comment - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * 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 - fun validate(): FeedbackProjectLogsItem = apply { - if (!validated) { - id() - scores()?.validate() - expected() - comment() - metadata()?.validate() - source() - validated = true - } - } + /** + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [source]. + * + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - return other is FeedbackProjectLogsItem && - this.id == other.id && - this.scores == other.scores && - this.expected == other.expected && - this.comment == other.comment && - this.metadata == other.metadata && - this.source == other.source && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - scores, - expected, - comment, - metadata, - source, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "FeedbackProjectLogsItem{id=$id, scores=$scores, expected=$expected, comment=$comment, metadata=$metadata, source=$source, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [FeedbackProjectLogsItem]. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FeedbackProjectLogsItem]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() + private var id: JsonField? = null private var comment: JsonField = JsonMissing.of() + private var expected: JsonValue = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() + private var scores: JsonField = JsonMissing.of() private var source: JsonField = JsonMissing.of() + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(feedbackProjectLogsItem: FeedbackProjectLogsItem) = apply { - this.id = feedbackProjectLogsItem.id - this.scores = feedbackProjectLogsItem.scores - this.expected = feedbackProjectLogsItem.expected - this.comment = feedbackProjectLogsItem.comment - this.metadata = feedbackProjectLogsItem.metadata - this.source = feedbackProjectLogsItem.source - additionalProperties(feedbackProjectLogsItem.additionalProperties) + id = feedbackProjectLogsItem.id + comment = feedbackProjectLogsItem.comment + expected = feedbackProjectLogsItem.expected + metadata = feedbackProjectLogsItem.metadata + scores = feedbackProjectLogsItem.scores + source = feedbackProjectLogsItem.source + tags = feedbackProjectLogsItem.tags.map { it.toMutableList() } + additionalProperties = feedbackProjectLogsItem.additionalProperties.toMutableMap() } /** @@ -178,283 +197,433 @@ private constructor( fun id(id: String) = id(JsonField.of(id)) /** - * The id of the project logs event to log feedback for. This is the row `id` returned by - * `POST /v1/project_logs/{project_id}/insert` + * 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. */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } + fun id(id: JsonField) = apply { this.id = id } - /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into - * the existing scores for the project logs event - */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) + /** An optional comment string to log about the project logs event */ + fun comment(comment: String?) = comment(JsonField.ofNullable(comment)) /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into - * the existing scores for the project logs event + * Sets [Builder.comment] to an arbitrary JSON value. + * + * You should usually call [Builder.comment] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } + fun comment(comment: JsonField) = apply { this.comment = comment } /** * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to * `output` to determine if your `output` value is correct or not */ - @JsonProperty("expected") - @ExcludeMissing fun expected(expected: JsonValue) = apply { this.expected = expected } - /** An optional comment string to log about the project logs event */ - fun comment(comment: String) = comment(JsonField.of(comment)) - - /** An optional comment string to log about the project logs event */ - @JsonProperty("comment") - @ExcludeMissing - fun comment(comment: JsonField) = apply { this.comment = comment } - /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can - * log it here and access it in the Braintrust UI. + * log it here and access it in the Braintrust UI. Note, this metadata does not correspond + * to the main event itself, but rather the audit log attached to the event. */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) /** - * A dictionary with additional data about the feedback. If you have a `user_id`, you can - * log it here and access it in the Braintrust UI. + * 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. */ - @JsonProperty("metadata") - @ExcludeMissing fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - fun source(source: Source) = source(JsonField.of(source)) + /** + * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into + * the existing scores for the project logs event + */ + fun scores(scores: Scores?) = scores(JsonField.ofNullable(scores)) + + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun scores(scores: JsonField) = apply { this.scores = scores } /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ - @JsonProperty("source") - @ExcludeMissing + fun source(source: Source?) = source(JsonField.ofNullable(source)) + + /** + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [Source] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun source(source: JsonField) = apply { this.source = source } + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FeedbackProjectLogsItem]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FeedbackProjectLogsItem = FeedbackProjectLogsItem( - id, - scores, - expected, + checkRequired("id", id), comment, + expected, metadata, + scores, source, - additionalProperties.toUnmodifiable(), + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): FeedbackProjectLogsItem = apply { + if (validated) { + return@apply + } + + id() + comment() + metadata()?.validate() + scores()?.validate() + source()?.validate() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (comment.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (scores.asKnown()?.validity() ?: 0) + + (source.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + /** * A dictionary with additional data about the feedback. If you have a `user_id`, you can log it - * here and access it in the Braintrust UI. + * here and access it in the Braintrust UI. Note, this metadata does not correspond to the main + * event itself, but rather the audit log attached to the event. */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - /** - * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the - * existing scores for the project logs event - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { + 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 - private var hashCode: Int = 0 + fun validate(): Metadata = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): Scores = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Scores && this.additionalProperties == other.additionalProperties + return other is Metadata && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "Scores{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + } + + /** + * A dictionary of numeric values (between 0 and 1) to log. These scores will be merged into the + * existing scores for the project logs event + */ + class Scores + @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 [Scores]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Scores]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) + additionalProperties = scores.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) } - } - class Source - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Scores = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Source && this.value == other.value + return other is Scores && additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = "Scores{additionalProperties=$additionalProperties}" + } + + /** The source of the feedback. Must be one of "external" (default), "app", or "api" */ + class Source @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 { - val APP = Source(JsonField.of("app")) + val APP = of("app") - val API = Source(JsonField.of("api")) + val API = of("api") - val EXTERNAL = Source(JsonField.of("external")) + val EXTERNAL = of("external") fun of(value: String) = Source(JsonField.of(value)) } + /** An enum containing [Source]'s known values. */ enum class Known { APP, API, EXTERNAL, } + /** + * An enum containing [Source]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Source] 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 { APP, API, EXTERNAL, + /** An enum member indicating that [Source] 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) { APP -> Value.APP @@ -463,6 +632,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { APP -> Known.APP @@ -471,6 +649,80 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown Source: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Source = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Source && 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 FeedbackProjectLogsItem && + id == other.id && + comment == other.comment && + expected == other.expected && + metadata == other.metadata && + scores == other.scores && + source == other.source && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, comment, expected, metadata, scores, source, tags, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FeedbackProjectLogsItem{id=$id, comment=$comment, expected=$expected, metadata=$metadata, scores=$scores, source=$source, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackResponseSchema.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackResponseSchema.kt index 032632d2..3f79c351 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackResponseSchema.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FeedbackResponseSchema.kt @@ -7,152 +7,283 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FeedbackResponseSchema.Builder::class) -@NoAutoDetect class FeedbackResponseSchema +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val status: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of() + ) : this(status, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("status") @ExcludeMissing fun _status() = status + /** + * 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 + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FeedbackResponseSchema = apply { - if (!validated) { - status() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FeedbackResponseSchema && - this.status == other.status && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(status, additionalProperties) - } - return hashCode - } - - override fun toString() = - "FeedbackResponseSchema{status=$status, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [FeedbackResponseSchema]. + * + * The following fields are required: + * ```kotlin + * .status() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FeedbackResponseSchema]. */ + class Builder internal constructor() { - private var status: JsonField = JsonMissing.of() + private var status: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(feedbackResponseSchema: FeedbackResponseSchema) = apply { - this.status = feedbackResponseSchema.status - additionalProperties(feedbackResponseSchema.additionalProperties) + status = feedbackResponseSchema.status + additionalProperties = feedbackResponseSchema.additionalProperties.toMutableMap() } fun status(status: Status) = status(JsonField.of(status)) - @JsonProperty("status") - @ExcludeMissing + /** + * 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 } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FeedbackResponseSchema]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .status() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FeedbackResponseSchema = - FeedbackResponseSchema(status, additionalProperties.toUnmodifiable()) + FeedbackResponseSchema( + checkRequired("status", status), + additionalProperties.toMutableMap(), + ) } - class Status - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): FeedbackResponseSchema = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + status().validate() + validated = true + } - return other is Status && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (status.asKnown()?.validity() ?: 0) + + 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 { - val SUCCESS = Status(JsonField.of("success")) + val SUCCESS = of("success") fun of(value: String) = Status(JsonField.of(value)) } + /** An enum containing [Status]'s known values. */ enum class Known { - SUCCESS, + SUCCESS } + /** + * 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 { SUCCESS, + /** 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) { SUCCESS -> Value.SUCCESS 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { SUCCESS -> Known.SUCCESS else -> throw BraintrustInvalidDataException("Unknown Status: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FeedbackResponseSchema && + status == other.status && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(status, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FeedbackResponseSchema{status=$status, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponse.kt index aa79a366..58bc3151 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponse.kt @@ -6,28 +6,39 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FetchDatasetEventsResponse.Builder::class) -@NoAutoDetect class FetchDatasetEventsResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val events: JsonField>, private val cursor: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("events") + @ExcludeMissing + events: JsonField> = JsonMissing.of(), + @JsonProperty("cursor") @ExcludeMissing cursor: JsonField = JsonMissing.of(), + ) : this(events, cursor, mutableMapOf()) - /** A list of fetched events */ + /** + * A list of fetched events + * + * @throws BraintrustInvalidDataException 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 events(): List = events.getRequired("events") /** @@ -35,92 +46,89 @@ private constructor( * * Pass this string directly as the `cursor` param to your next fetch request to get the next * page of results. Not provided if the returned result set is empty. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun cursor(): String? = cursor.getNullable("cursor") - /** A list of fetched events */ - @JsonProperty("events") @ExcludeMissing fun _events() = events + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("events") @ExcludeMissing fun _events(): JsonField> = events /** - * Pagination cursor + * Returns the raw JSON value of [cursor]. * - * Pass this string directly as the `cursor` param to your next fetch request to get the next - * page of results. Not provided if the returned result set is empty. + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("cursor") @ExcludeMissing fun _cursor() = cursor + @JsonProperty("cursor") @ExcludeMissing fun _cursor(): JsonField = cursor + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FetchDatasetEventsResponse = apply { - if (!validated) { - events().forEach { it.validate() } - cursor() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FetchDatasetEventsResponse && - this.events == other.events && - this.cursor == other.cursor && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - events, - cursor, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "FetchDatasetEventsResponse{events=$events, cursor=$cursor, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [FetchDatasetEventsResponse]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FetchDatasetEventsResponse]. */ + class Builder internal constructor() { - private var events: JsonField> = JsonMissing.of() + private var events: JsonField>? = null private var cursor: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(fetchDatasetEventsResponse: FetchDatasetEventsResponse) = apply { - this.events = fetchDatasetEventsResponse.events - this.cursor = fetchDatasetEventsResponse.cursor - additionalProperties(fetchDatasetEventsResponse.additionalProperties) + events = fetchDatasetEventsResponse.events.map { it.toMutableList() } + cursor = fetchDatasetEventsResponse.cursor + additionalProperties = fetchDatasetEventsResponse.additionalProperties.toMutableMap() } /** A list of fetched events */ fun events(events: List) = events(JsonField.of(events)) - /** A list of fetched events */ - @JsonProperty("events") - @ExcludeMissing - fun events(events: JsonField>) = apply { this.events = events } + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun events(events: JsonField>) = apply { + this.events = events.map { it.toMutableList() } + } /** - * Pagination cursor + * Adds a single [DatasetEvent] to [events]. * - * Pass this string directly as the `cursor` param to your next fetch request to get the - * next page of results. Not provided if the returned result set is empty. + * @throws IllegalStateException if the field was previously set to a non-list. */ - fun cursor(cursor: String) = cursor(JsonField.of(cursor)) + fun addEvent(event: DatasetEvent) = apply { + events = + (events ?: JsonField.of(mutableListOf())).also { + checkKnown("events", it).add(event) + } + } /** * Pagination cursor @@ -128,29 +136,99 @@ private constructor( * Pass this string directly as the `cursor` param to your next fetch request to get the * next page of results. Not provided if the returned result set is empty. */ - @JsonProperty("cursor") - @ExcludeMissing + fun cursor(cursor: String?) = cursor(JsonField.ofNullable(cursor)) + + /** + * Sets [Builder.cursor] to an arbitrary JSON value. + * + * You should usually call [Builder.cursor] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun cursor(cursor: JsonField) = apply { this.cursor = cursor } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FetchDatasetEventsResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FetchDatasetEventsResponse = FetchDatasetEventsResponse( - events.map { it.toUnmodifiable() }, + checkRequired("events", events).map { it.toImmutable() }, cursor, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): FetchDatasetEventsResponse = apply { + if (validated) { + return@apply + } + + events().forEach { it.validate() } + cursor() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (events.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (if (cursor.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FetchDatasetEventsResponse && + events == other.events && + cursor == other.cursor && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(events, cursor, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FetchDatasetEventsResponse{events=$events, cursor=$cursor, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponse.kt index f680bafc..30897c44 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponse.kt @@ -6,28 +6,39 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FetchExperimentEventsResponse.Builder::class) -@NoAutoDetect class FetchExperimentEventsResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val events: JsonField>, private val cursor: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("events") + @ExcludeMissing + events: JsonField> = JsonMissing.of(), + @JsonProperty("cursor") @ExcludeMissing cursor: JsonField = JsonMissing.of(), + ) : this(events, cursor, mutableMapOf()) - /** A list of fetched events */ + /** + * A list of fetched events + * + * @throws BraintrustInvalidDataException 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 events(): List = events.getRequired("events") /** @@ -35,92 +46,90 @@ private constructor( * * Pass this string directly as the `cursor` param to your next fetch request to get the next * page of results. Not provided if the returned result set is empty. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun cursor(): String? = cursor.getNullable("cursor") - /** A list of fetched events */ - @JsonProperty("events") @ExcludeMissing fun _events() = events + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("events") @ExcludeMissing fun _events(): JsonField> = events /** - * Pagination cursor + * Returns the raw JSON value of [cursor]. * - * Pass this string directly as the `cursor` param to your next fetch request to get the next - * page of results. Not provided if the returned result set is empty. + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("cursor") @ExcludeMissing fun _cursor() = cursor + @JsonProperty("cursor") @ExcludeMissing fun _cursor(): JsonField = cursor + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FetchExperimentEventsResponse = apply { - if (!validated) { - events().forEach { it.validate() } - cursor() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FetchExperimentEventsResponse && - this.events == other.events && - this.cursor == other.cursor && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - events, - cursor, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "FetchExperimentEventsResponse{events=$events, cursor=$cursor, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [FetchExperimentEventsResponse]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FetchExperimentEventsResponse]. */ + class Builder internal constructor() { - private var events: JsonField> = JsonMissing.of() + private var events: JsonField>? = null private var cursor: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(fetchExperimentEventsResponse: FetchExperimentEventsResponse) = apply { - this.events = fetchExperimentEventsResponse.events - this.cursor = fetchExperimentEventsResponse.cursor - additionalProperties(fetchExperimentEventsResponse.additionalProperties) + events = fetchExperimentEventsResponse.events.map { it.toMutableList() } + cursor = fetchExperimentEventsResponse.cursor + additionalProperties = fetchExperimentEventsResponse.additionalProperties.toMutableMap() } /** A list of fetched events */ fun events(events: List) = events(JsonField.of(events)) - /** A list of fetched events */ - @JsonProperty("events") - @ExcludeMissing - fun events(events: JsonField>) = apply { this.events = events } + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun events(events: JsonField>) = apply { + this.events = events.map { it.toMutableList() } + } /** - * Pagination cursor + * Adds a single [ExperimentEvent] to [events]. * - * Pass this string directly as the `cursor` param to your next fetch request to get the - * next page of results. Not provided if the returned result set is empty. + * @throws IllegalStateException if the field was previously set to a non-list. */ - fun cursor(cursor: String) = cursor(JsonField.of(cursor)) + fun addEvent(event: ExperimentEvent) = apply { + events = + (events ?: JsonField.of(mutableListOf())).also { + checkKnown("events", it).add(event) + } + } /** * Pagination cursor @@ -128,29 +137,99 @@ private constructor( * Pass this string directly as the `cursor` param to your next fetch request to get the * next page of results. Not provided if the returned result set is empty. */ - @JsonProperty("cursor") - @ExcludeMissing + fun cursor(cursor: String?) = cursor(JsonField.ofNullable(cursor)) + + /** + * Sets [Builder.cursor] to an arbitrary JSON value. + * + * You should usually call [Builder.cursor] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun cursor(cursor: JsonField) = apply { this.cursor = cursor } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FetchExperimentEventsResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FetchExperimentEventsResponse = FetchExperimentEventsResponse( - events.map { it.toUnmodifiable() }, + checkRequired("events", events).map { it.toImmutable() }, cursor, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): FetchExperimentEventsResponse = apply { + if (validated) { + return@apply + } + + events().forEach { it.validate() } + cursor() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (events.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (if (cursor.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FetchExperimentEventsResponse && + events == other.events && + cursor == other.cursor && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(events, cursor, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FetchExperimentEventsResponse{events=$events, cursor=$cursor, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponse.kt index cfb690b7..13ec4132 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponse.kt @@ -6,28 +6,39 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FetchProjectLogsEventsResponse.Builder::class) -@NoAutoDetect class FetchProjectLogsEventsResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val events: JsonField>, private val cursor: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("events") + @ExcludeMissing + events: JsonField> = JsonMissing.of(), + @JsonProperty("cursor") @ExcludeMissing cursor: JsonField = JsonMissing.of(), + ) : this(events, cursor, mutableMapOf()) - /** A list of fetched events */ + /** + * A list of fetched events + * + * @throws BraintrustInvalidDataException 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 events(): List = events.getRequired("events") /** @@ -35,92 +46,93 @@ private constructor( * * Pass this string directly as the `cursor` param to your next fetch request to get the next * page of results. Not provided if the returned result set is empty. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun cursor(): String? = cursor.getNullable("cursor") - /** A list of fetched events */ - @JsonProperty("events") @ExcludeMissing fun _events() = events - /** - * Pagination cursor + * Returns the raw JSON value of [events]. * - * Pass this string directly as the `cursor` param to your next fetch request to get the next - * page of results. Not provided if the returned result set is empty. + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("cursor") @ExcludeMissing fun _cursor() = cursor - - @JsonAnyGetter + @JsonProperty("events") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FetchProjectLogsEventsResponse = apply { - if (!validated) { - events().forEach { it.validate() } - cursor() - validated = true - } - } + fun _events(): JsonField> = events - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [cursor]. + * + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cursor") @ExcludeMissing fun _cursor(): JsonField = cursor - return other is FetchProjectLogsEventsResponse && - this.events == other.events && - this.cursor == other.cursor && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - events, - cursor, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "FetchProjectLogsEventsResponse{events=$events, cursor=$cursor, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of + * [FetchProjectLogsEventsResponse]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FetchProjectLogsEventsResponse]. */ + class Builder internal constructor() { - private var events: JsonField> = JsonMissing.of() + private var events: JsonField>? = null private var cursor: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(fetchProjectLogsEventsResponse: FetchProjectLogsEventsResponse) = apply { - this.events = fetchProjectLogsEventsResponse.events - this.cursor = fetchProjectLogsEventsResponse.cursor - additionalProperties(fetchProjectLogsEventsResponse.additionalProperties) + events = fetchProjectLogsEventsResponse.events.map { it.toMutableList() } + cursor = fetchProjectLogsEventsResponse.cursor + additionalProperties = + fetchProjectLogsEventsResponse.additionalProperties.toMutableMap() } /** A list of fetched events */ fun events(events: List) = events(JsonField.of(events)) - /** A list of fetched events */ - @JsonProperty("events") - @ExcludeMissing - fun events(events: JsonField>) = apply { this.events = events } + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun events(events: JsonField>) = apply { + this.events = events.map { it.toMutableList() } + } /** - * Pagination cursor + * Adds a single [ProjectLogsEvent] to [events]. * - * Pass this string directly as the `cursor` param to your next fetch request to get the - * next page of results. Not provided if the returned result set is empty. + * @throws IllegalStateException if the field was previously set to a non-list. */ - fun cursor(cursor: String) = cursor(JsonField.of(cursor)) + fun addEvent(event: ProjectLogsEvent) = apply { + events = + (events ?: JsonField.of(mutableListOf())).also { + checkKnown("events", it).add(event) + } + } /** * Pagination cursor @@ -128,29 +140,99 @@ private constructor( * Pass this string directly as the `cursor` param to your next fetch request to get the * next page of results. Not provided if the returned result set is empty. */ - @JsonProperty("cursor") - @ExcludeMissing + fun cursor(cursor: String?) = cursor(JsonField.ofNullable(cursor)) + + /** + * Sets [Builder.cursor] to an arbitrary JSON value. + * + * You should usually call [Builder.cursor] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun cursor(cursor: JsonField) = apply { this.cursor = cursor } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FetchProjectLogsEventsResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FetchProjectLogsEventsResponse = FetchProjectLogsEventsResponse( - events.map { it.toUnmodifiable() }, + checkRequired("events", events).map { it.toImmutable() }, cursor, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): FetchProjectLogsEventsResponse = apply { + if (validated) { + return@apply + } + + events().forEach { it.validate() } + cursor() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (events.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (if (cursor.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FetchProjectLogsEventsResponse && + events == other.events && + cursor == other.cursor && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(events, cursor, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FetchProjectLogsEventsResponse{events=$events, cursor=$cursor, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Function.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Function.kt index d92ca9d7..56c885b1 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Function.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Function.kt @@ -9,9 +9,11 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -25,265 +27,408 @@ 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.util.Collections import java.util.Objects -@JsonDeserialize(builder = Function.Builder::class) -@NoAutoDetect class Function +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val _xactId: JsonField, - private val projectId: JsonField, + private val functionData: JsonField, private val logId: JsonField, - private val orgId: JsonField, private val name: JsonField, + private val orgId: JsonField, + private val projectId: JsonField, private val slug: JsonField, - private val description: JsonField, private val created: JsonField, - private val promptData: JsonField, - private val tags: JsonField>, - private val metadata: JsonField, + private val description: JsonField, + private val functionSchema: JsonField, private val functionType: JsonField, - private val functionData: JsonField, + private val metadata: JsonField, private val origin: JsonField, - private val functionSchema: JsonField, - private val additionalProperties: Map, + private val promptData: JsonField, + private val tags: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_xact_id") @ExcludeMissing _xactId: JsonField = JsonMissing.of(), + @JsonProperty("function_data") + @ExcludeMissing + functionData: JsonField = JsonMissing.of(), + @JsonProperty("log_id") @ExcludeMissing logId: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("function_schema") + @ExcludeMissing + functionSchema: JsonField = JsonMissing.of(), + @JsonProperty("function_type") + @ExcludeMissing + functionType: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("origin") @ExcludeMissing origin: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _xactId, + functionData, + logId, + name, + orgId, + projectId, + slug, + created, + description, + functionSchema, + functionType, + metadata, + origin, + promptData, + tags, + mutableMapOf(), + ) - /** Unique identifier for the prompt */ + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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") /** * The transaction id of an event is unique to the network operation that processed the event * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve * a versioned snapshot of the prompt (see the `version` parameter) + * + * @throws BraintrustInvalidDataException 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 _xactId(): String = _xactId.getRequired("_xact_id") - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(): String = projectId.getRequired("project_id") + /** + * @throws BraintrustInvalidDataException 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 functionData(): FunctionData = functionData.getRequired("function_data") - /** A literal 'p' which identifies the object as a project prompt */ + /** + * A literal 'p' which identifies the object as a project prompt + * + * @throws BraintrustInvalidDataException 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 logId(): LogId = logId.getRequired("log_id") - /** Unique identifier for the organization */ + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the organization + * + * @throws BraintrustInvalidDataException 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 orgId(): String = orgId.getRequired("org_id") - /** Name of the prompt */ - fun name(): String = name.getRequired("name") + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** Unique identifier for the prompt */ + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") - /** Textual description of the prompt */ - fun description(): String? = description.getNullable("description") - - /** Date of prompt creation */ + /** + * Date of prompt creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** The prompt, model, and its parameters */ - fun promptData(): PromptData? = promptData.getNullable("prompt_data") - - /** A list of tags for the prompt */ - fun tags(): List? = tags.getNullable("tags") + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - /** User-controlled metadata about the prompt */ - fun metadata(): Metadata? = metadata.getNullable("metadata") + /** + * JSON schema for the function's parameters and return type + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionSchema(): FunctionSchema? = functionSchema.getNullable("function_schema") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun functionType(): FunctionType? = functionType.getNullable("function_type") - fun functionData(): FunctionData = functionData.getRequired("function_data") + /** + * User-controlled metadata about the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun origin(): Origin? = origin.getNullable("origin") - /** JSON schema for the function's parameters and return type */ - fun functionSchema(): FunctionSchema? = functionSchema.getNullable("function_schema") - - /** Unique identifier for the prompt */ - @JsonProperty("id") @ExcludeMissing fun _id() = id + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") /** - * The transaction id of an event is unique to the network operation that processed the event - * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve - * a versioned snapshot of the prompt (see the `version` parameter) + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("_xact_id") @ExcludeMissing fun __xactId() = _xactId + fun tags(): List? = tags.getNullable("tags") - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId + /** + * 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 - /** A literal 'p' which identifies the object as a project prompt */ - @JsonProperty("log_id") @ExcludeMissing fun _logId() = logId + /** + * Returns the raw JSON value of [_xactId]. + * + * Unlike [_xactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_xact_id") @ExcludeMissing fun __xactId(): JsonField = _xactId - /** Unique identifier for the organization */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId + /** + * Returns the raw JSON value of [functionData]. + * + * Unlike [functionData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("function_data") + @ExcludeMissing + fun _functionData(): JsonField = functionData - /** Name of the prompt */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [logId]. + * + * Unlike [logId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("log_id") @ExcludeMissing fun _logId(): JsonField = logId - /** Unique identifier for the prompt */ - @JsonProperty("slug") @ExcludeMissing fun _slug() = slug + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Textual description of the prompt */ - @JsonProperty("description") @ExcludeMissing fun _description() = description + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId - /** Date of prompt creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * 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 - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") @ExcludeMissing fun _promptData() = promptData + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug - /** A list of tags for the prompt */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - /** User-controlled metadata about the prompt */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata + /** + * 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 - @JsonProperty("function_type") @ExcludeMissing fun _functionType() = functionType + /** + * Returns the raw JSON value of [functionSchema]. + * + * Unlike [functionSchema], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("function_schema") + @ExcludeMissing + fun _functionSchema(): JsonField = functionSchema - @JsonProperty("function_data") @ExcludeMissing fun _functionData() = functionData + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("function_type") + @ExcludeMissing + fun _functionType(): JsonField = functionType - @JsonProperty("origin") @ExcludeMissing fun _origin() = origin + /** + * 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 - /** JSON schema for the function's parameters and return type */ - @JsonProperty("function_schema") @ExcludeMissing fun _functionSchema() = functionSchema + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin - @JsonAnyGetter + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - id() - _xactId() - projectId() - logId() - orgId() - name() - slug() - description() - created() - promptData()?.validate() - tags() - metadata()?.validate() - functionType() - functionData() - origin()?.validate() - functionSchema()?.validate() - validated = true - } - } - - fun toBuilder() = Builder().from(this) + fun _promptData(): JsonField = promptData - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - return other is Function && - this.id == other.id && - this._xactId == other._xactId && - this.projectId == other.projectId && - this.logId == other.logId && - this.orgId == other.orgId && - this.name == other.name && - this.slug == other.slug && - this.description == other.description && - this.created == other.created && - this.promptData == other.promptData && - this.tags == other.tags && - this.metadata == other.metadata && - this.functionType == other.functionType && - this.functionData == other.functionData && - this.origin == other.origin && - this.functionSchema == other.functionSchema && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - _xactId, - projectId, - logId, - orgId, - name, - slug, - description, - created, - promptData, - tags, - metadata, - functionType, - functionData, - origin, - functionSchema, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Function{id=$id, _xactId=$_xactId, projectId=$projectId, logId=$logId, orgId=$orgId, name=$name, slug=$slug, description=$description, created=$created, promptData=$promptData, tags=$tags, metadata=$metadata, functionType=$functionType, functionData=$functionData, origin=$origin, functionSchema=$functionSchema, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Function]. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .functionData() + * .logId() + * .name() + * .orgId() + * .projectId() + * .slug() + * ``` + */ fun builder() = Builder() } - class Builder { - - private var id: JsonField = JsonMissing.of() - private var _xactId: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var logId: JsonField = JsonMissing.of() - private var orgId: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var slug: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() + /** A builder for [Function]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var _xactId: JsonField? = null + private var functionData: JsonField? = null + private var logId: JsonField? = null + private var name: JsonField? = null + private var orgId: JsonField? = null + private var projectId: JsonField? = null + private var slug: JsonField? = null private var created: JsonField = JsonMissing.of() - private var promptData: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var functionSchema: JsonField = JsonMissing.of() private var functionType: JsonField = JsonMissing.of() - private var functionData: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() private var origin: JsonField = JsonMissing.of() - private var functionSchema: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(function: Function) = apply { - this.id = function.id - this._xactId = function._xactId - this.projectId = function.projectId - this.logId = function.logId - this.orgId = function.orgId - this.name = function.name - this.slug = function.slug - this.description = function.description - this.created = function.created - this.promptData = function.promptData - this.tags = function.tags - this.metadata = function.metadata - this.functionType = function.functionType - this.functionData = function.functionData - this.origin = function.origin - this.functionSchema = function.functionSchema - additionalProperties(function.additionalProperties) + id = function.id + _xactId = function._xactId + functionData = function.functionData + logId = function.logId + name = function.name + orgId = function.orgId + projectId = function.projectId + slug = function.slug + created = function.created + description = function.description + functionSchema = function.functionSchema + functionType = function.functionType + metadata = function.metadata + origin = function.origin + promptData = function.promptData + tags = function.tags.map { it.toMutableList() } + additionalProperties = function.additionalProperties.toMutableMap() } /** Unique identifier for the prompt */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the prompt */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } /** * The transaction id of an event is unique to the network operation that processed the @@ -293,163 +438,318 @@ private constructor( fun _xactId(_xactId: String) = _xactId(JsonField.of(_xactId)) /** - * The transaction id of an event is unique to the network operation that processed the - * event insertion. Transaction ids are monotonically increasing over time and can be used - * to retrieve a versioned snapshot of the prompt (see the `version` parameter) + * Sets [Builder._xactId] to an arbitrary JSON value. + * + * You should usually call [Builder._xactId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("_xact_id") - @ExcludeMissing fun _xactId(_xactId: JsonField) = apply { this._xactId = _xactId } - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) + fun functionData(functionData: FunctionData) = functionData(JsonField.of(functionData)) - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") - @ExcludeMissing - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } + /** + * Sets [Builder.functionData] to an arbitrary JSON value. + * + * You should usually call [Builder.functionData] with a well-typed [FunctionData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionData(functionData: JsonField) = apply { + this.functionData = functionData + } + + /** Alias for calling [functionData] with `FunctionData.ofPrompt(prompt)`. */ + fun functionData(prompt: FunctionData.Prompt) = functionData(FunctionData.ofPrompt(prompt)) + + /** Alias for calling [functionData] with `FunctionData.ofCode(code)`. */ + fun functionData(code: FunctionData.Code) = functionData(FunctionData.ofCode(code)) + + /** Alias for calling [functionData] with `FunctionData.ofGlobal(global)`. */ + fun functionData(global: FunctionData.Global) = functionData(FunctionData.ofGlobal(global)) /** A literal 'p' which identifies the object as a project prompt */ fun logId(logId: LogId) = logId(JsonField.of(logId)) - /** A literal 'p' which identifies the object as a project prompt */ - @JsonProperty("log_id") - @ExcludeMissing + /** + * Sets [Builder.logId] to an arbitrary JSON value. + * + * You should usually call [Builder.logId] with a well-typed [LogId] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun logId(logId: JsonField) = apply { this.logId = logId } + /** Name of the prompt */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + /** Unique identifier for the organization */ fun orgId(orgId: String) = orgId(JsonField.of(orgId)) - /** Unique identifier for the organization */ - @JsonProperty("org_id") - @ExcludeMissing + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun orgId(orgId: JsonField) = apply { this.orgId = orgId } - /** Name of the prompt */ - fun name(name: String) = name(JsonField.of(name)) + /** Unique identifier for the project that the prompt belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Name of the prompt */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + /** + * 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 } /** Unique identifier for the prompt */ fun slug(slug: String) = slug(JsonField.of(slug)) - /** Unique identifier for the prompt */ - @JsonProperty("slug") - @ExcludeMissing + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun slug(slug: JsonField) = apply { this.slug = slug } - /** Textual description of the prompt */ - fun description(description: String) = description(JsonField.of(description)) - - /** Textual description of the prompt */ - @JsonProperty("description") - @ExcludeMissing - fun description(description: JsonField) = apply { this.description = description } - /** Date of prompt creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) - /** Date of prompt creation */ - @JsonProperty("created") - @ExcludeMissing + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = promptData(JsonField.of(promptData)) - - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - @ExcludeMissing - fun promptData(promptData: JsonField) = apply { this.promptData = promptData } - - /** A list of tags for the prompt */ - fun tags(tags: List) = tags(JsonField.of(tags)) + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(description)) - /** A list of tags for the prompt */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } + /** + * 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 } - /** User-controlled metadata about the prompt */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + /** JSON schema for the function's parameters and return type */ + fun functionSchema(functionSchema: FunctionSchema?) = + functionSchema(JsonField.ofNullable(functionSchema)) - /** User-controlled metadata about the prompt */ - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } + /** + * Sets [Builder.functionSchema] to an arbitrary JSON value. + * + * You should usually call [Builder.functionSchema] with a well-typed [FunctionSchema] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionSchema(functionSchema: JsonField) = apply { + this.functionSchema = functionSchema + } - fun functionType(functionType: FunctionType) = functionType(JsonField.of(functionType)) + fun functionType(functionType: FunctionType?) = + functionType(JsonField.ofNullable(functionType)) - @JsonProperty("function_type") - @ExcludeMissing + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun functionType(functionType: JsonField) = apply { this.functionType = functionType } - fun functionData(functionData: FunctionData) = functionData(JsonField.of(functionData)) + /** User-controlled metadata about the prompt */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) - @JsonProperty("function_data") - @ExcludeMissing - fun functionData(functionData: JsonField) = apply { - this.functionData = functionData - } + /** + * 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 origin(origin: Origin) = origin(JsonField.of(origin)) + fun origin(origin: Origin?) = origin(JsonField.ofNullable(origin)) - @JsonProperty("origin") - @ExcludeMissing + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [Origin] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun origin(origin: JsonField) = apply { this.origin = origin } - /** JSON schema for the function's parameters and return type */ - fun functionSchema(functionSchema: FunctionSchema) = - functionSchema(JsonField.of(functionSchema)) + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) - /** JSON schema for the function's parameters and return type */ - @JsonProperty("function_schema") - @ExcludeMissing - fun functionSchema(functionSchema: JsonField) = apply { - this.functionSchema = functionSchema + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { this.promptData = promptData } + + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .functionData() + * .logId() + * .name() + * .orgId() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Function = Function( - id, - _xactId, - projectId, - logId, - orgId, - name, - slug, - description, + checkRequired("id", id), + checkRequired("_xactId", _xactId), + checkRequired("functionData", functionData), + checkRequired("logId", logId), + checkRequired("name", name), + checkRequired("orgId", orgId), + checkRequired("projectId", projectId), + checkRequired("slug", slug), created, - promptData, - tags.map { it.toUnmodifiable() }, - metadata, + description, + functionSchema, functionType, - functionData, + metadata, origin, - functionSchema, - additionalProperties.toUnmodifiable(), + promptData, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Function = apply { + if (validated) { + return@apply + } + + id() + _xactId() + functionData().validate() + logId().validate() + name() + orgId() + projectId() + slug() + created() + description() + functionSchema()?.validate() + functionType()?.validate() + metadata()?.validate() + origin()?.validate() + promptData()?.validate() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_xactId.asKnown() == null) 0 else 1) + + (functionData.asKnown()?.validity() ?: 0) + + (logId.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (functionSchema.asKnown()?.validity() ?: 0) + + (functionType.asKnown()?.validity() ?: 0) + + (metadata.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (promptData.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + @JsonDeserialize(using = FunctionData.Deserializer::class) @JsonSerialize(using = FunctionData.Serializer::class) class FunctionData @@ -460,8 +760,6 @@ private constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun prompt(): Prompt? = prompt fun code(): Code? = code @@ -482,26 +780,65 @@ private constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { prompt != null -> visitor.visitPrompt(prompt) code != null -> visitor.visitCode(code) global != null -> visitor.visitGlobal(global) else -> visitor.unknown(_json) } + + private var validated: Boolean = false + + fun validate(): FunctionData = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) { + prompt.validate() + } + + override fun visitCode(code: Code) { + code.validate() + } + + override fun visitGlobal(global: Global) { + global.validate() + } + } + ) + validated = true } - fun validate(): FunctionData = apply { - if (!validated) { - if (prompt == null && code == null && global == null) { - throw BraintrustInvalidDataException("Unknown FunctionData: $_json") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) = prompt.validity() + + override fun visitCode(code: Code) = code.validity() + + override fun visitGlobal(global: Global) = global.validity() + + override fun unknown(json: JsonValue?) = 0 } - prompt?.validate() - code?.validate() - global?.validate() - validated = true - } - } + ) override fun equals(other: Any?): Boolean { if (this === other) { @@ -509,28 +846,21 @@ private constructor( } return other is FunctionData && - this.prompt == other.prompt && - this.code == other.code && - this.global == other.global + prompt == other.prompt && + code == other.code && + global == other.global } - override fun hashCode(): Int { - return Objects.hash( - prompt, - code, - global, - ) - } + override fun hashCode(): Int = Objects.hash(prompt, code, global) - override fun toString(): String { - return when { + override fun toString(): String = + when { prompt != null -> "FunctionData{prompt=$prompt}" code != null -> "FunctionData{code=$code}" global != null -> "FunctionData{global=$global}" _json != null -> "FunctionData{_unknown=$_json}" else -> throw IllegalStateException("Invalid FunctionData") } - } companion object { @@ -541,6 +871,10 @@ private constructor( fun ofGlobal(global: Global) = FunctionData(global = global) } + /** + * An interface that defines how to map each variant of [FunctionData] to a value of type + * [T]. + */ interface Visitor { fun visitPrompt(prompt: Prompt): T @@ -549,38 +883,60 @@ private constructor( fun visitGlobal(global: Global): T + /** + * Maps an unknown variant of [FunctionData] to a value of type [T]. + * + * An instance of [FunctionData] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown FunctionData: $json") } } - class Deserializer : BaseDeserializer(FunctionData::class) { + internal class Deserializer : BaseDeserializer(FunctionData::class) { override fun ObjectCodec.deserialize(node: JsonNode): FunctionData { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(prompt = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(code = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(global = it, _json = json) - } - return FunctionData(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(prompt = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(code = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(global = 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 -> FunctionData(_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() + } } } - class Serializer : BaseSerializer(FunctionData::class) { + internal class Serializer : BaseSerializer(FunctionData::class) { override fun serialize( value: FunctionData, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.prompt != null -> generator.writeObject(value.prompt) @@ -592,84 +948,86 @@ private constructor( } } - @JsonDeserialize(builder = Prompt.Builder::class) - @NoAutoDetect class Prompt + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of() + ) : this(type, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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 = additionalProperties - - fun validate(): Prompt = apply { - if (!validated) { - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Prompt && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(type, additionalProperties) - } - return hashCode - } - - override fun toString() = - "Prompt{type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Prompt]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Prompt]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(prompt: Prompt) = apply { - this.type = prompt.type - additionalProperties(prompt.additionalProperties) + type = prompt.type + additionalProperties = prompt.additionalProperties.toMutableMap() } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -677,159 +1035,314 @@ private constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Prompt = Prompt(type, additionalProperties.toUnmodifiable()) - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns an immutable instance of [Prompt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Prompt = + Prompt(checkRequired("type", type), additionalProperties.toMutableMap()) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Type && this.value == other.value + fun validate(): Prompt = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() + type().validate() + validated = true + } - override fun toString() = value.toString() + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (type.asKnown()?.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 { - val PROMPT = Type(JsonField.of("prompt")) + val PROMPT = of("prompt") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - PROMPT, + PROMPT } + /** + * 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 { PROMPT, + /** + * 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) { PROMPT -> Value.PROMPT 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { PROMPT -> Known.PROMPT else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Code.Builder::class) - @NoAutoDetect - class Code - private constructor( - private val type: JsonField, - private val data: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun data(): Data = data.getRequired("data") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("data") @ExcludeMissing fun _data() = data + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Code = apply { - if (!validated) { - type() - data() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Code && - this.type == other.type && - this.data == other.data && - this.additionalProperties == other.additionalProperties + return other is Prompt && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - data, - additionalProperties, - ) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(type, additionalProperties) } + + override fun hashCode(): Int = hashCode override fun toString() = - "Code{type=$type, data=$data, additionalProperties=$additionalProperties}" + "Prompt{type=$type, additionalProperties=$additionalProperties}" + } + + class Code + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val data: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(data, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 BraintrustInvalidDataException 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 [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 [Code]. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Code]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var data: JsonField = JsonMissing.of() + private var data: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(code: Code) = apply { - this.type = code.type - this.data = code.data - additionalProperties(code.additionalProperties) + data = code.data + type = code.type + additionalProperties = code.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun data(data: Data) = data(JsonField.of(data)) - @JsonProperty("data") - @ExcludeMissing + /** + * 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.ofBundle(bundle)`. */ + fun data(bundle: Data.Bundle) = data(Data.ofBundle(bundle)) + + /** Alias for calling [data] with `Data.ofInline(inline)`. */ + fun data(inline: Data.Inline) = data(Data.ofInline(inline)) + + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -837,14 +1350,64 @@ private constructor( 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 [Code]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Code = Code( - type, - data, - additionalProperties.toUnmodifiable(), + checkRequired("data", data), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Code = apply { + if (validated) { + return@apply + } + + data().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (data.asKnown()?.validity() ?: 0) + (type.asKnown()?.validity() ?: 0) + @JsonDeserialize(using = Data.Deserializer::class) @JsonSerialize(using = Data.Serializer::class) class Data @@ -854,8 +1417,6 @@ private constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun bundle(): Bundle? = bundle fun inline(): Inline? = inline @@ -870,46 +1431,76 @@ private constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { bundle != null -> visitor.visitBundle(bundle) inline != null -> visitor.visitInline(inline) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Data = apply { - if (!validated) { - if (bundle == null && inline == null) { - throw BraintrustInvalidDataException("Unknown Data: $_json") - } - inline?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) { + bundle.validate() + } + + override fun visitInline(inline: Inline) { + inline.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) = bundle.validity() + + override fun visitInline(inline: Inline) = inline.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Data && - this.bundle == other.bundle && - this.inline == other.inline + return other is Data && bundle == other.bundle && inline == other.inline } - override fun hashCode(): Int { - return Objects.hash(bundle, inline) - } + override fun hashCode(): Int = Objects.hash(bundle, inline) - override fun toString(): String { - return when { + override fun toString(): String = + when { bundle != null -> "Data{bundle=$bundle}" inline != null -> "Data{inline=$inline}" _json != null -> "Data{_unknown=$_json}" else -> throw IllegalStateException("Invalid Data") } - } companion object { @@ -918,39 +1509,68 @@ private constructor( fun ofInline(inline: Inline) = Data(inline = inline) } + /** + * An interface that defines how to map each variant of [Data] to a value of type + * [T]. + */ interface Visitor { fun visitBundle(bundle: Bundle): T fun visitInline(inline: Inline): 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Data: $json") } } - class Deserializer : BaseDeserializer(Data::class) { + internal class Deserializer : BaseDeserializer(Data::class) { override fun ObjectCodec.deserialize(node: JsonNode): Data { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Data(bundle = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Data(inline = it, _json = json) - } - return Data(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Data(bundle = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Data(inline = 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() + } } } - class Serializer : BaseSerializer(Data::class) { + internal class Serializer : BaseSerializer(Data::class) { override fun serialize( value: Data, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.bundle != null -> generator.writeObject(value.bundle) @@ -961,477 +1581,840 @@ private constructor( } } - @JsonDeserialize(builder = Bundle.Builder::class) - @NoAutoDetect class Bundle + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val runtimeContext: JsonField, - private val location: JsonField, private val bundleId: JsonField, + private val location: JsonField, + private val runtimeContext: JsonField, private val preview: JsonField, private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun runtimeContext(): CodeBundle.RuntimeContext = - runtimeContext.getRequired("runtime_context") - - fun location(): CodeBundle.Location = location.getRequired("location") - - fun bundleId(): String = bundleId.getRequired("bundle_id") - - /** A preview of the code */ - fun preview(): String? = preview.getNullable("preview") - - fun type(): Type = type.getRequired("type") + @JsonCreator + private constructor( + @JsonProperty("bundle_id") + @ExcludeMissing + bundleId: JsonField = JsonMissing.of(), + @JsonProperty("location") + @ExcludeMissing + location: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("preview") + @ExcludeMissing + preview: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(bundleId, location, runtimeContext, preview, type, mutableMapOf()) fun toCodeBundle(): CodeBundle = CodeBundle.builder() - .runtimeContext(runtimeContext) - .location(location) .bundleId(bundleId) + .location(location) + .runtimeContext(runtimeContext) .preview(preview) .build() - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + /** + * @throws BraintrustInvalidDataException 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 bundleId(): String = bundleId.getRequired("bundle_id") - @JsonProperty("location") @ExcludeMissing fun _location() = location + /** + * @throws BraintrustInvalidDataException 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 location(): CodeBundle.Location = location.getRequired("location") - @JsonProperty("bundle_id") @ExcludeMissing fun _bundleId() = bundleId + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): CodeBundle.RuntimeContext = + runtimeContext.getRequired("runtime_context") - /** A preview of the code */ - @JsonProperty("preview") @ExcludeMissing fun _preview() = preview + /** + * A preview of the code + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun preview(): String? = preview.getNullable("preview") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * @throws BraintrustInvalidDataException 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") - @JsonAnyGetter + /** + * Returns the raw JSON value of [bundleId]. + * + * Unlike [bundleId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("bundle_id") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Bundle = apply { - if (!validated) { - runtimeContext().validate() - location() - bundleId() - preview() - type() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Bundle && - this.runtimeContext == other.runtimeContext && - this.location == other.location && - this.bundleId == other.bundleId && - this.preview == other.preview && - this.type == other.type && - this.additionalProperties == other.additionalProperties + fun _bundleId(): JsonField = bundleId + + /** + * 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 [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * Returns the raw JSON value of [preview]. + * + * Unlike [preview], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("preview") + @ExcludeMissing + fun _preview(): JsonField = preview + + /** + * 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) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtimeContext, - location, - bundleId, - preview, - type, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Bundle{runtimeContext=$runtimeContext, location=$location, bundleId=$bundleId, preview=$preview, type=$type, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Bundle]. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Bundle]. */ + class Builder internal constructor() { - private var runtimeContext: JsonField = - JsonMissing.of() - private var location: JsonField = JsonMissing.of() - private var bundleId: JsonField = JsonMissing.of() + private var bundleId: JsonField? = null + private var location: JsonField? = null + private var runtimeContext: JsonField? = null private var preview: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(bundle: Bundle) = apply { - this.runtimeContext = bundle.runtimeContext - this.location = bundle.location - this.bundleId = bundle.bundleId - this.preview = bundle.preview - this.type = bundle.type - additionalProperties(bundle.additionalProperties) + bundleId = bundle.bundleId + location = bundle.location + runtimeContext = bundle.runtimeContext + preview = bundle.preview + type = bundle.type + additionalProperties = bundle.additionalProperties.toMutableMap() } - fun runtimeContext(runtimeContext: CodeBundle.RuntimeContext) = - runtimeContext(JsonField.of(runtimeContext)) + fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - @JsonProperty("runtime_context") - @ExcludeMissing - fun runtimeContext(runtimeContext: JsonField) = - apply { - this.runtimeContext = runtimeContext - } + /** + * Sets [Builder.bundleId] to an arbitrary JSON value. + * + * You should usually call [Builder.bundleId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun bundleId(bundleId: JsonField) = apply { + this.bundleId = bundleId + } fun location(location: CodeBundle.Location) = location(JsonField.of(location)) - @JsonProperty("location") - @ExcludeMissing + /** + * Sets [Builder.location] to an arbitrary JSON value. + * + * You should usually call [Builder.location] with a well-typed + * [CodeBundle.Location] 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 } - fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofExperiment(experiment)`. + */ + fun location(experiment: CodeBundle.Location.Experiment) = + location(CodeBundle.Location.ofExperiment(experiment)) - @JsonProperty("bundle_id") - @ExcludeMissing - fun bundleId(bundleId: JsonField) = apply { - this.bundleId = bundleId - } + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofFunction(function)`. + */ + fun location(function: CodeBundle.Location.Function) = + location(CodeBundle.Location.ofFunction(function)) - /** A preview of the code */ - fun preview(preview: String) = preview(JsonField.of(preview)) + fun runtimeContext(runtimeContext: CodeBundle.RuntimeContext) = + runtimeContext(JsonField.of(runtimeContext)) + + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [CodeBundle.RuntimeContext] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun runtimeContext(runtimeContext: JsonField) = + apply { + this.runtimeContext = runtimeContext + } /** A preview of the code */ - @JsonProperty("preview") - @ExcludeMissing + fun preview(preview: String?) = preview(JsonField.ofNullable(preview)) + + /** + * Sets [Builder.preview] to an arbitrary JSON value. + * + * You should usually call [Builder.preview] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun preview(preview: JsonField) = apply { this.preview = preview } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Bundle]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Bundle = Bundle( - runtimeContext, - location, - bundleId, + checkRequired("bundleId", bundleId), + checkRequired("location", location), + checkRequired("runtimeContext", runtimeContext), preview, - type, - additionalProperties.toUnmodifiable(), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Bundle = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + bundleId() + location().validate() + runtimeContext().validate() + preview() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (bundleId.asKnown() == null) 0 else 1) + + (location.asKnown()?.validity() ?: 0) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (if (preview.asKnown() == null) 0 else 1) + + (type.asKnown()?.validity() ?: 0) - override fun toString() = value.toString() + 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 { - val BUNDLE = Type(JsonField.of("bundle")) + val BUNDLE = of("bundle") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - BUNDLE, + BUNDLE } + /** + * 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 { BUNDLE, + /** + * 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) { BUNDLE -> Value.BUNDLE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { BUNDLE -> Known.BUNDLE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - - @JsonDeserialize(builder = Inline.Builder::class) - @NoAutoDetect - class Inline - private constructor( - private val type: JsonField, - private val runtimeContext: JsonField, - private val code: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - private var hashCode: Int = 0 + private var validated: Boolean = false - fun type(): Type = type.getRequired("type") + fun validate(): Type = apply { + if (validated) { + return@apply + } - fun runtimeContext(): RuntimeContext = - runtimeContext.getRequired("runtime_context") + known() + validated = true + } - fun code(): String = code.getRequired("code") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("code") @ExcludeMissing fun _code() = code + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Inline = apply { - if (!validated) { - type() - runtimeContext().validate() - code() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Inline && - this.type == other.type && - this.runtimeContext == other.runtimeContext && - this.code == other.code && - this.additionalProperties == other.additionalProperties + return other is Bundle && + bundleId == other.bundleId && + location == other.location && + runtimeContext == other.runtimeContext && + preview == other.preview && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - runtimeContext, - code, - additionalProperties, - ) - } - return hashCode + private val hashCode: Int by lazy { + Objects.hash( + bundleId, + location, + runtimeContext, + preview, + type, + additionalProperties, + ) } + override fun hashCode(): Int = hashCode + override fun toString() = - "Inline{type=$type, runtimeContext=$runtimeContext, code=$code, additionalProperties=$additionalProperties}" + "Bundle{bundleId=$bundleId, location=$location, runtimeContext=$runtimeContext, preview=$preview, type=$type, additionalProperties=$additionalProperties}" + } + + class Inline + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val code: JsonField, + private val runtimeContext: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("code") + @ExcludeMissing + code: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(code, runtimeContext, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 code(): String = code.getRequired("code") + + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): RuntimeContext = + runtimeContext.getRequired("runtime_context") + + /** + * @throws BraintrustInvalidDataException 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 [code]. + * + * Unlike [code], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("code") @ExcludeMissing fun _code(): JsonField = code + + /** + * Returns the raw JSON value of [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * 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 [Inline]. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Inline]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var runtimeContext: JsonField = JsonMissing.of() - private var code: JsonField = JsonMissing.of() + private var code: JsonField? = null + private var runtimeContext: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inline: Inline) = apply { - this.type = inline.type - this.runtimeContext = inline.runtimeContext - this.code = inline.code - additionalProperties(inline.additionalProperties) + code = inline.code + runtimeContext = inline.runtimeContext + type = inline.type + additionalProperties = inline.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) + fun code(code: String) = code(JsonField.of(code)) - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } + /** + * Sets [Builder.code] to an arbitrary JSON value. + * + * You should usually call [Builder.code] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun code(code: JsonField) = apply { this.code = code } fun runtimeContext(runtimeContext: RuntimeContext) = runtimeContext(JsonField.of(runtimeContext)) - @JsonProperty("runtime_context") - @ExcludeMissing + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [RuntimeContext] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ fun runtimeContext(runtimeContext: JsonField) = apply { this.runtimeContext = runtimeContext } - fun code(code: String) = code(JsonField.of(code)) + fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("code") - @ExcludeMissing - fun code(code: JsonField) = apply { this.code = code } + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Inline]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Inline = Inline( - type, - runtimeContext, - code, - additionalProperties.toUnmodifiable(), + checkRequired("code", code), + checkRequired("runtimeContext", runtimeContext), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = RuntimeContext.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): Inline = apply { + if (validated) { + return@apply + } + + code() + runtimeContext().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (code.asKnown() == null) 0 else 1) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (type.asKnown()?.validity() ?: 0) + class RuntimeContext + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val runtime: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("runtime") + @ExcludeMissing + runtime: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(runtime, version, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 runtime(): Runtime = runtime.getRequired("runtime") + /** + * @throws BraintrustInvalidDataException 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 version(): String = version.getRequired("version") - @JsonProperty("runtime") @ExcludeMissing fun _runtime() = runtime + /** + * Returns the raw JSON value of [runtime]. + * + * Unlike [runtime], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime") + @ExcludeMissing + fun _runtime(): JsonField = runtime + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("version") + @ExcludeMissing + fun _version(): JsonField = version - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): RuntimeContext = apply { - if (!validated) { - runtime() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RuntimeContext && - this.runtime == other.runtime && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtime, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [RuntimeContext]. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RuntimeContext]. */ + class Builder internal constructor() { - private var runtime: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() + private var runtime: JsonField? = null + private var version: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(runtimeContext: RuntimeContext) = apply { - this.runtime = runtimeContext.runtime - this.version = runtimeContext.version - additionalProperties(runtimeContext.additionalProperties) + runtime = runtimeContext.runtime + version = runtimeContext.version + additionalProperties = + runtimeContext.additionalProperties.toMutableMap() } fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) - @JsonProperty("runtime") - @ExcludeMissing + /** + * Sets [Builder.runtime] to an arbitrary JSON value. + * + * You should usually call [Builder.runtime] with a well-typed [Runtime] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun runtime(runtime: JsonField) = apply { this.runtime = runtime } fun version(version: String) = version(JsonField.of(version)) - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } @@ -1439,67 +2422,136 @@ private constructor( fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RuntimeContext]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RuntimeContext = RuntimeContext( - runtime, - version, - additionalProperties.toUnmodifiable(), + checkRequired("runtime", runtime), + checkRequired("version", version), + additionalProperties.toMutableMap(), ) } - class Runtime - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): RuntimeContext = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + runtime().validate() + version() + validated = true + } - return other is Runtime && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (runtime.asKnown()?.validity() ?: 0) + + (if (version.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Runtime + @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 { - val NODE = Runtime(JsonField.of("node")) + val NODE = of("node") - val PYTHON = Runtime(JsonField.of("python")) + val PYTHON = of("python") fun of(value: String) = Runtime(JsonField.of(value)) } + /** An enum containing [Runtime]'s known values. */ enum class Known { NODE, PYTHON, } + /** + * An enum containing [Runtime]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Runtime] 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 { NODE, PYTHON, + /** + * An enum member indicating that [Runtime] 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) { NODE -> Value.NODE @@ -1507,6 +2559,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value + * is a not a known member. + */ fun known(): Known = when (this) { NODE -> Known.NODE @@ -1517,214 +2578,482 @@ private constructor( ) } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Runtime = apply { + if (validated) { + return@apply + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + 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 Runtime && 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 Type && this.value == other.value + return other is RuntimeContext && + runtime == other.runtime && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(runtime, version, additionalProperties) } - override fun hashCode() = value.hashCode() + override fun hashCode(): Int = hashCode - override fun toString() = value.toString() + override fun toString() = + "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + } + + 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 { - val INLINE = Type(JsonField.of("inline")) + val INLINE = of("inline") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - INLINE, + INLINE } + /** + * 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 { INLINE, + /** + * 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) { INLINE -> Value.INLINE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { INLINE -> Known.INLINE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + return other is Inline && + code == other.code && + runtimeContext == other.runtimeContext && + type == other.type && + additionalProperties == other.additionalProperties + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + private val hashCode: Int by lazy { + Objects.hash(code, runtimeContext, type, additionalProperties) } - return other is Type && this.value == other.value - } + override fun hashCode(): Int = hashCode - override fun hashCode() = value.hashCode() + override fun toString() = + "Inline{code=$code, runtimeContext=$runtimeContext, type=$type, additionalProperties=$additionalProperties}" + } + } - override fun toString() = value.toString() + 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 { - val CODE = Type(JsonField.of("code")) + val CODE = of("code") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - CODE, + CODE } + /** + * 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 { CODE, + /** + * 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) { CODE -> Value.CODE 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { CODE -> Known.CODE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Global.Builder::class) - @NoAutoDetect - class Global - private constructor( - private val type: JsonField, - private val name: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun name(): String = name.getRequired("name") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("name") @ExcludeMissing fun _name() = name + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Global = apply { - if (!validated) { - type() - name() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Global && - this.type == other.type && - this.name == other.name && - this.additionalProperties == other.additionalProperties + return other is Code && + data == other.data && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - name, - additionalProperties, - ) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(data, type, additionalProperties) } + + override fun hashCode(): Int = hashCode override fun toString() = - "Global{type=$type, name=$name, additionalProperties=$additionalProperties}" + "Code{data=$data, type=$type, additionalProperties=$additionalProperties}" + } + + class Global + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [Global]. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Global]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var name: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(global: Global) = apply { - this.type = global.type - this.name = global.name - additionalProperties(global.additionalProperties) + name = global.name + type = global.type + additionalProperties = global.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1732,261 +3061,483 @@ private constructor( 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 [Global]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Global = Global( - type, - name, - additionalProperties.toUnmodifiable(), + checkRequired("name", name), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Global = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val GLOBAL = Type(JsonField.of("global")) + val GLOBAL = of("global") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - GLOBAL, + GLOBAL } + /** + * 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 { GLOBAL, + /** + * 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) { GLOBAL -> Value.GLOBAL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { GLOBAL -> Known.GLOBAL else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - class LogId - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Type = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Global && + name == other.name && + type == other.type && + additionalProperties == other.additionalProperties } - return other is LogId && this.value == other.value + private val hashCode: Int by lazy { Objects.hash(name, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Global{name=$name, type=$type, additionalProperties=$additionalProperties}" } + } - override fun hashCode() = value.hashCode() + /** A literal 'p' which identifies the object as a project prompt */ + class LogId @JsonCreator private constructor(private val value: JsonField) : Enum { - override fun toString() = value.toString() + /** + * 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 { - val P = LogId(JsonField.of("p")) + val P = of("p") fun of(value: String) = LogId(JsonField.of(value)) } + /** An enum containing [LogId]'s known values. */ enum class Known { - P, + P } + /** + * An enum containing [LogId]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [LogId] 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 { P, + /** An enum member indicating that [LogId] 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) { P -> Value.P 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { P -> Known.P else -> throw BraintrustInvalidDataException("Unknown LogId: $value") } - fun asString(): String = _value().asStringOrThrow() - } - - /** JSON schema for the function's parameters and return type */ - @JsonDeserialize(builder = FunctionSchema.Builder::class) - @NoAutoDetect - class FunctionSchema - private constructor( - private val parameters: JsonValue, - private val returns: JsonValue, - private val additionalProperties: Map, - ) { + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") private var validated: Boolean = false - private var hashCode: Int = 0 - - fun parameters(): JsonValue = parameters - - fun returns(): JsonValue = returns - - @JsonProperty("parameters") @ExcludeMissing fun _parameters() = parameters - - @JsonProperty("returns") @ExcludeMissing fun _returns() = returns + fun validate(): LogId = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + known() + validated = true + } - fun validate(): FunctionSchema = apply { - if (!validated) { - parameters() - returns() - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FunctionSchema && - this.parameters == other.parameters && - this.returns == other.returns && - this.additionalProperties == other.additionalProperties - } + return other is LogId && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** JSON schema for the function's parameters and return type */ + class FunctionSchema + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val parameters: JsonValue, + private val returns: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("parameters") @ExcludeMissing parameters: JsonValue = JsonMissing.of(), + @JsonProperty("returns") @ExcludeMissing returns: JsonValue = JsonMissing.of(), + ) : this(parameters, returns, mutableMapOf()) + + @JsonProperty("parameters") @ExcludeMissing fun _parameters(): JsonValue = parameters - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - parameters, - returns, - additionalProperties, - ) - } - return hashCode + @JsonProperty("returns") @ExcludeMissing fun _returns(): JsonValue = returns + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "FunctionSchema{parameters=$parameters, returns=$returns, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [FunctionSchema]. */ fun builder() = Builder() } - class Builder { + /** A builder for [FunctionSchema]. */ + class Builder internal constructor() { private var parameters: JsonValue = JsonMissing.of() private var returns: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(functionSchema: FunctionSchema) = apply { - this.parameters = functionSchema.parameters - this.returns = functionSchema.returns - additionalProperties(functionSchema.additionalProperties) + parameters = functionSchema.parameters + returns = functionSchema.returns + additionalProperties = functionSchema.additionalProperties.toMutableMap() } - @JsonProperty("parameters") - @ExcludeMissing fun parameters(parameters: JsonValue) = apply { this.parameters = parameters } - @JsonProperty("returns") - @ExcludeMissing fun returns(returns: JsonValue) = apply { this.returns = returns } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FunctionSchema]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): FunctionSchema = - FunctionSchema( - parameters, - returns, - additionalProperties.toUnmodifiable(), - ) + FunctionSchema(parameters, returns, additionalProperties.toMutableMap()) } - } - class FunctionType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): FunctionSchema = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = 0 override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is FunctionType && this.value == other.value + return other is FunctionSchema && + parameters == other.parameters && + returns == other.returns && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash(parameters, returns, additionalProperties) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "FunctionSchema{parameters=$parameters, returns=$returns, additionalProperties=$additionalProperties}" + } + + class FunctionType @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 { - val LLM = FunctionType(JsonField.of("llm")) + val LLM = of("llm") - val SCORER = FunctionType(JsonField.of("scorer")) + val SCORER = of("scorer") - val TASK = FunctionType(JsonField.of("task")) + val TASK = of("task") - val TOOL = FunctionType(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = FunctionType(JsonField.of(value)) } + /** An enum containing [FunctionType]'s known values. */ enum class Known { LLM, SCORER, @@ -1994,14 +3545,33 @@ private constructor( TOOL, } + /** + * An enum containing [FunctionType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [FunctionType] 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 { LLM, SCORER, TASK, TOOL, + /** + * An enum member indicating that [FunctionType] 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) { LLM -> Value.LLM @@ -2011,6 +3581,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { LLM -> Known.LLM @@ -2020,345 +3599,459 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown FunctionType: $value") } - fun asString(): String = _value().asStringOrThrow() - } - - /** User-controlled metadata about the prompt */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): FunctionType = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + known() + validated = true + } - fun validate(): Metadata = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Metadata && this.additionalProperties == other.additionalProperties + return other is FunctionType && value == other.value } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + override fun hashCode() = value.hashCode() - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + override fun toString() = value.toString() + } + + /** User-controlled metadata about the prompt */ + 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]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" } - @JsonDeserialize(builder = Origin.Builder::class) - @NoAutoDetect class Origin + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val objectType: JsonField, private val objectId: JsonField, + private val objectType: JsonField, private val internal_: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The object type that the ACL applies to */ - fun objectType(): ObjectType = objectType.getRequired("object_type") + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("internal") + @ExcludeMissing + internal_: JsonField = JsonMissing.of(), + ) : this(objectId, objectType, internal_, mutableMapOf()) - /** Id of the object the function is originating from */ + /** + * Id of the object the function is originating from + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") + /** * The function exists for internal purposes and should not be displayed in the list of * functions. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ fun internal_(): Boolean? = internal_.getNullable("internal") - /** The object type that the ACL applies to */ - @JsonProperty("object_type") @ExcludeMissing fun _objectType() = objectType - - /** Id of the object the function is originating from */ - @JsonProperty("object_id") @ExcludeMissing fun _objectId() = objectId - /** - * The function exists for internal purposes and should not be displayed in the list of - * functions. + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("internal") @ExcludeMissing fun _internal_() = internal_ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - @JsonAnyGetter + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Origin = apply { - if (!validated) { - objectType() - objectId() - internal_() - validated = true - } - } + fun _objectType(): JsonField = objectType - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [internal_]. + * + * Unlike [internal_], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("internal") @ExcludeMissing fun _internal_(): JsonField = internal_ - return other is Origin && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.internal_ == other.internal_ && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectType, - objectId, - internal_, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Origin{objectType=$objectType, objectId=$objectId, internal_=$internal_, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Origin]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Origin]. */ + class Builder internal constructor() { - private var objectType: JsonField = JsonMissing.of() - private var objectId: JsonField = JsonMissing.of() + private var objectId: JsonField? = null + private var objectType: JsonField? = null private var internal_: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(origin: Origin) = apply { - this.objectType = origin.objectType - this.objectId = origin.objectId - this.internal_ = origin.internal_ - additionalProperties(origin.additionalProperties) - } - - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) - - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - @ExcludeMissing - fun objectType(objectType: JsonField) = apply { - this.objectType = objectType + objectId = origin.objectId + objectType = origin.objectType + internal_ = origin.internal_ + additionalProperties = origin.additionalProperties.toMutableMap() } /** Id of the object the function is originating from */ fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - /** Id of the object the function is originating from */ - @JsonProperty("object_id") - @ExcludeMissing + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) + /** - * The function exists for internal purposes and should not be displayed in the list of - * functions. + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun internal_(internal_: Boolean) = internal_(JsonField.of(internal_)) + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } /** * The function exists for internal purposes and should not be displayed in the list of * functions. */ - @JsonProperty("internal") - @ExcludeMissing + fun internal_(internal_: Boolean?) = internal_(JsonField.ofNullable(internal_)) + + /** + * Alias for [Builder.internal_]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun internal_(internal_: Boolean) = internal_(internal_ as Boolean?) + + /** + * Sets [Builder.internal_] to an arbitrary JSON value. + * + * You should usually call [Builder.internal_] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun internal_(internal_: JsonField) = apply { this.internal_ = internal_ } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Origin]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Origin = Origin( - objectType, - objectId, + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), internal_, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is ObjectType && this.value == other.value + fun validate(): Origin = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val EXPERIMENT = ObjectType(JsonField.of("experiment")) - - val DATASET = ObjectType(JsonField.of("dataset")) - - val PROMPT = ObjectType(JsonField.of("prompt")) + objectId() + objectType().validate() + internal_() + validated = true + } - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - val GROUP = ObjectType(JsonField.of("group")) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (internal_.asKnown() == null) 0 else 1) - val ROLE = ObjectType(JsonField.of("role")) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + return other is Origin && + objectId == other.objectId && + objectType == other.objectType && + internal_ == other.internal_ && + additionalProperties == other.additionalProperties + } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + private val hashCode: Int by lazy { + Objects.hash(objectId, objectType, internal_, additionalProperties) + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + override fun hashCode(): Int = hashCode - fun of(value: String) = ObjectType(JsonField.of(value)) - } + override fun toString() = + "Origin{objectId=$objectId, objectType=$objectType, internal_=$internal_, additionalProperties=$additionalProperties}" + } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + return other is Function && + id == other.id && + _xactId == other._xactId && + functionData == other.functionData && + logId == other.logId && + name == other.name && + orgId == other.orgId && + projectId == other.projectId && + slug == other.slug && + created == other.created && + description == other.description && + functionSchema == other.functionSchema && + functionType == other.functionType && + metadata == other.metadata && + origin == other.origin && + promptData == other.promptData && + tags == other.tags && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { + Objects.hash( + id, + _xactId, + functionData, + logId, + name, + orgId, + projectId, + slug, + created, + description, + functionSchema, + functionType, + metadata, + origin, + promptData, + tags, + additionalProperties, + ) + } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "Function{id=$id, _xactId=$_xactId, functionData=$functionData, logId=$logId, name=$name, orgId=$orgId, projectId=$projectId, slug=$slug, created=$created, description=$description, functionSchema=$functionSchema, functionType=$functionType, metadata=$metadata, origin=$origin, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionCreateParams.kt index 3819bdb2..3014aeab 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionCreateParams.kt @@ -9,9 +9,14 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.braintrustdata.api.models.CodeBundle.* import com.fasterxml.jackson.annotation.JsonAnyGetter @@ -25,291 +30,542 @@ 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 +/** + * Create a new function. If there is an existing function in the project with the same slug as the + * one specified in the request, will return the existing function unmodified + */ class FunctionCreateParams -constructor( - private val functionData: FunctionData, - private val name: String, - private val projectId: String, - private val slug: String, - private val description: String?, - private val functionSchema: FunctionSchema?, - private val functionType: FunctionType?, - private val origin: Origin?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * @throws BraintrustInvalidDataException 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 functionData(): FunctionData = body.functionData() + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = body.slug() + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * JSON schema for the function's parameters and return type + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionSchema(): FunctionSchema? = body.functionSchema() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionType(): FunctionType? = body.functionType() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun origin(): Origin? = body.origin() + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = body.promptData() + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = body.tags() + + /** + * Returns the raw JSON value of [functionData]. + * + * Unlike [functionData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionData(): JsonField = body._functionData() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _slug(): JsonField = body._slug() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [functionSchema]. + * + * Unlike [functionSchema], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionSchema(): JsonField = body._functionSchema() + + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionType(): JsonField = body._functionType() + + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _origin(): JsonField = body._origin() + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _promptData(): JsonField = body._promptData() + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tags(): JsonField> = body._tags() + + 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 functionData(): FunctionData = functionData - - fun name(): String = name - - fun projectId(): String = projectId + fun toBuilder() = Builder().from(this) - fun slug(): String = slug + companion object { - fun description(): String? = description + /** + * Returns a mutable builder for constructing an instance of [FunctionCreateParams]. + * + * The following fields are required: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() + } - fun functionSchema(): FunctionSchema? = functionSchema + /** A builder for [FunctionCreateParams]. */ + class Builder internal constructor() { - fun functionType(): FunctionType? = functionType + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun origin(): Origin? = origin + internal fun from(functionCreateParams: FunctionCreateParams) = apply { + body = functionCreateParams.body.toBuilder() + additionalHeaders = functionCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = functionCreateParams.additionalQueryParams.toBuilder() + } - fun promptData(): PromptData? = promptData + /** + * 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: + * - [functionData] + * - [name] + * - [projectId] + * - [slug] + * - [description] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } - fun tags(): List? = tags + fun functionData(functionData: FunctionData) = apply { body.functionData(functionData) } - internal fun getBody(): FunctionCreateBody { - return FunctionCreateBody( - functionData, - name, - projectId, - slug, - description, - functionSchema, - functionType, - origin, - promptData, - tags, - additionalBodyProperties, - ) - } + /** + * Sets [Builder.functionData] to an arbitrary JSON value. + * + * You should usually call [Builder.functionData] with a well-typed [FunctionData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionData(functionData: JsonField) = apply { + body.functionData(functionData) + } - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = FunctionCreateBody.Builder::class) - @NoAutoDetect - class FunctionCreateBody - internal constructor( - private val functionData: FunctionData?, - private val name: String?, - private val projectId: String?, - private val slug: String?, - private val description: String?, - private val functionSchema: FunctionSchema?, - private val functionType: FunctionType?, - private val origin: Origin?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalProperties: Map, - ) { + /** Alias for calling [functionData] with `FunctionData.ofPrompt(prompt)`. */ + fun functionData(prompt: FunctionData.Prompt) = apply { body.functionData(prompt) } - private var hashCode: Int = 0 + /** Alias for calling [functionData] with `FunctionData.ofCode(code)`. */ + fun functionData(code: FunctionData.Code) = apply { body.functionData(code) } - @JsonProperty("function_data") fun functionData(): FunctionData? = functionData + /** Alias for calling [functionData] with `FunctionData.ofGlobal(global)`. */ + fun functionData(global: FunctionData.Global) = apply { body.functionData(global) } /** Name of the prompt */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(): String? = slug + fun slug(slug: String) = apply { body.slug(slug) } + + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun slug(slug: JsonField) = apply { body.slug(slug) } /** Textual description of the prompt */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** JSON schema for the function's parameters and return type */ - @JsonProperty("function_schema") fun functionSchema(): FunctionSchema? = functionSchema + fun functionSchema(functionSchema: FunctionSchema?) = apply { + body.functionSchema(functionSchema) + } + + /** + * Sets [Builder.functionSchema] to an arbitrary JSON value. + * + * You should usually call [Builder.functionSchema] with a well-typed [FunctionSchema] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionSchema(functionSchema: JsonField) = apply { + body.functionSchema(functionSchema) + } - @JsonProperty("function_type") fun functionType(): FunctionType? = functionType + fun functionType(functionType: FunctionType?) = apply { body.functionType(functionType) } - @JsonProperty("origin") fun origin(): Origin? = origin + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + body.functionType(functionType) + } + + fun origin(origin: Origin?) = apply { body.origin(origin) } + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [Origin] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun origin(origin: JsonField) = apply { body.origin(origin) } /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") fun promptData(): PromptData? = promptData + fun promptData(promptData: PromptData?) = apply { body.promptData(promptData) } + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { body.promptData(promptData) } /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(): List? = tags + fun tags(tags: List?) = apply { body.tags(tags) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { body.tags(tags) } - fun toBuilder() = Builder().from(this) + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { body.addTag(tag) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - return other is FunctionCreateBody && - this.functionData == other.functionData && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionSchema == other.functionSchema && - this.functionType == other.functionType && - this.origin == other.origin && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalProperties == other.additionalProperties + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - functionData, - name, - projectId, - slug, - description, - functionSchema, - functionType, - origin, - promptData, - tags, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "FunctionCreateBody{functionData=$functionData, name=$name, projectId=$projectId, slug=$slug, description=$description, functionSchema=$functionSchema, functionType=$functionType, origin=$origin, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { - - private var functionData: FunctionData? = null - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionSchema: FunctionSchema? = null - private var functionType: FunctionType? = null - private var origin: Origin? = null - private var promptData: PromptData? = null - private var tags: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - internal fun from(functionCreateBody: FunctionCreateBody) = apply { - this.functionData = functionCreateBody.functionData - this.name = functionCreateBody.name - this.projectId = functionCreateBody.projectId - this.slug = functionCreateBody.slug - this.description = functionCreateBody.description - this.functionSchema = functionCreateBody.functionSchema - this.functionType = functionCreateBody.functionType - this.origin = functionCreateBody.origin - this.promptData = functionCreateBody.promptData - this.tags = functionCreateBody.tags - additionalProperties(functionCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @JsonProperty("function_data") - fun functionData(functionData: FunctionData) = apply { - this.functionData = functionData - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the prompt */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(slug: String) = apply { this.slug = slug } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Textual description of the prompt */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** JSON schema for the function's parameters and return type */ - @JsonProperty("function_schema") - fun functionSchema(functionSchema: FunctionSchema) = apply { - this.functionSchema = functionSchema - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - @JsonProperty("function_type") - fun functionType(functionType: FunctionType) = apply { - this.functionType = functionType - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonProperty("origin") fun origin(origin: Origin) = apply { this.origin = origin } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(tags: List) = apply { this.tags = tags } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun build(): FunctionCreateBody = - FunctionCreateBody( - checkNotNull(functionData) { "`functionData` is required but was not set" }, - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, - description, - functionSchema, - functionType, - origin, - promptData, - tags?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is FunctionCreateParams && - this.functionData == other.functionData && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionSchema == other.functionSchema && - this.functionType == other.functionType && - this.origin == other.origin && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [FunctionCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionCreateParams = + FunctionCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( + 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 functionData: JsonField, + private val name: JsonField, + private val projectId: JsonField, + private val slug: JsonField, + private val description: JsonField, + private val functionSchema: JsonField, + private val functionType: JsonField, + private val origin: JsonField, + private val promptData: JsonField, + private val tags: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("function_data") + @ExcludeMissing + functionData: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("function_schema") + @ExcludeMissing + functionSchema: JsonField = JsonMissing.of(), + @JsonProperty("function_type") + @ExcludeMissing + functionType: JsonField = JsonMissing.of(), + @JsonProperty("origin") @ExcludeMissing origin: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( functionData, name, projectId, @@ -320,172 +576,510 @@ constructor( origin, promptData, tags, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - override fun toString() = - "FunctionCreateParams{functionData=$functionData, name=$name, projectId=$projectId, slug=$slug, description=$description, functionSchema=$functionSchema, functionType=$functionType, origin=$origin, promptData=$promptData, tags=$tags, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + /** + * @throws BraintrustInvalidDataException 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 functionData(): FunctionData = functionData.getRequired("function_data") - fun toBuilder() = Builder().from(this) + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - companion object { + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - fun builder() = Builder() - } + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") - @NoAutoDetect - class Builder { - - private var functionData: FunctionData? = null - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionSchema: FunctionSchema? = null - private var functionType: FunctionType? = null - private var origin: Origin? = null - private var promptData: PromptData? = null - private var tags: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - internal fun from(functionCreateParams: FunctionCreateParams) = apply { - this.functionData = functionCreateParams.functionData - this.name = functionCreateParams.name - this.projectId = functionCreateParams.projectId - this.slug = functionCreateParams.slug - this.description = functionCreateParams.description - this.functionSchema = functionCreateParams.functionSchema - this.functionType = functionCreateParams.functionType - this.origin = functionCreateParams.origin - this.promptData = functionCreateParams.promptData - this.tags(functionCreateParams.tags ?: listOf()) - additionalQueryParams(functionCreateParams.additionalQueryParams) - additionalHeaders(functionCreateParams.additionalHeaders) - additionalBodyProperties(functionCreateParams.additionalBodyProperties) - } + /** + * JSON schema for the function's parameters and return type + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun functionSchema(): FunctionSchema? = functionSchema.getNullable("function_schema") - fun functionData(functionData: FunctionData) = apply { this.functionData = functionData } + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun functionType(): FunctionType? = functionType.getNullable("function_type") - fun functionData(prompt: FunctionData.Prompt) = apply { - this.functionData = FunctionData.ofPrompt(prompt) - } + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun origin(): Origin? = origin.getNullable("origin") - fun functionData(code: FunctionData.Code) = apply { - this.functionData = FunctionData.ofCode(code) - } + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") - fun functionData(global: FunctionData.Global) = apply { - this.functionData = FunctionData.ofGlobal(global) - } + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") - /** Name of the prompt */ - fun name(name: String) = apply { this.name = name } + /** + * Returns the raw JSON value of [functionData]. + * + * Unlike [functionData], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_data") + @ExcludeMissing + fun _functionData(): JsonField = functionData - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Unique identifier for the prompt */ - fun slug(slug: String) = apply { this.slug = slug } + /** + * 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 - /** Textual description of the prompt */ - fun description(description: String) = apply { this.description = description } + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug - /** JSON schema for the function's parameters and return type */ - fun functionSchema(functionSchema: FunctionSchema) = apply { - this.functionSchema = functionSchema - } + /** + * 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 - fun functionType(functionType: FunctionType) = apply { this.functionType = functionType } + /** + * Returns the raw JSON value of [functionSchema]. + * + * Unlike [functionSchema], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_schema") + @ExcludeMissing + fun _functionSchema(): JsonField = functionSchema - fun origin(origin: Origin) = apply { this.origin = origin } + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_type") + @ExcludeMissing + fun _functionType(): JsonField = functionType - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin - /** A list of tags for the prompt */ - fun tags(tags: List) = apply { - this.tags.clear() - this.tags.addAll(tags) - } + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") + @ExcludeMissing + fun _promptData(): JsonField = promptData - /** A list of tags for the prompt */ - fun addTag(tag: String) = apply { this.tags.add(tag) } + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + companion object { - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var functionData: JsonField? = null + private var name: JsonField? = null + private var projectId: JsonField? = null + private var slug: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var functionSchema: JsonField = JsonMissing.of() + private var functionType: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + internal fun from(body: Body) = apply { + functionData = body.functionData + name = body.name + projectId = body.projectId + slug = body.slug + description = body.description + functionSchema = body.functionSchema + functionType = body.functionType + origin = body.origin + promptData = body.promptData + tags = body.tags.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun functionData(functionData: FunctionData) = functionData(JsonField.of(functionData)) - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** + * Sets [Builder.functionData] to an arbitrary JSON value. + * + * You should usually call [Builder.functionData] with a well-typed [FunctionData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionData(functionData: JsonField) = apply { + this.functionData = functionData + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** Alias for calling [functionData] with `FunctionData.ofPrompt(prompt)`. */ + fun functionData(prompt: FunctionData.Prompt) = + functionData(FunctionData.ofPrompt(prompt)) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Alias for calling [functionData] with `FunctionData.ofCode(code)`. */ + fun functionData(code: FunctionData.Code) = functionData(FunctionData.ofCode(code)) + + /** Alias for calling [functionData] with `FunctionData.ofGlobal(global)`. */ + fun functionData(global: FunctionData.Global) = + functionData(FunctionData.ofGlobal(global)) + + /** Name of the prompt */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Unique identifier for the project that the prompt belongs under */ + 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 } + + /** Unique identifier for the prompt */ + fun slug(slug: String) = slug(JsonField.of(slug)) + + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun slug(slug: JsonField) = apply { this.slug = slug } + + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** JSON schema for the function's parameters and return type */ + fun functionSchema(functionSchema: FunctionSchema?) = + functionSchema(JsonField.ofNullable(functionSchema)) + + /** + * Sets [Builder.functionSchema] to an arbitrary JSON value. + * + * You should usually call [Builder.functionSchema] with a well-typed [FunctionSchema] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun functionSchema(functionSchema: JsonField) = apply { + this.functionSchema = functionSchema + } + + fun functionType(functionType: FunctionType?) = + functionType(JsonField.ofNullable(functionType)) + + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + this.functionType = functionType + } + + fun origin(origin: Origin?) = origin(JsonField.ofNullable(origin)) + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [Origin] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun origin(origin: JsonField) = apply { this.origin = origin } + + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { + this.promptData = promptData + } + + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = + (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + + 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: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("functionData", functionData), + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("slug", slug), + description, + functionSchema, + functionType, + origin, + promptData, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + functionData().validate() + name() + projectId() + slug() + description() + functionSchema()?.validate() + functionType()?.validate() + origin()?.validate() + promptData()?.validate() + tags() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): FunctionCreateParams = - FunctionCreateParams( - checkNotNull(functionData) { "`functionData` is required but was not set" }, - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (functionData.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (functionSchema.asKnown()?.validity() ?: 0) + + (functionType.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (promptData.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + functionData == other.functionData && + name == other.name && + projectId == other.projectId && + slug == other.slug && + description == other.description && + functionSchema == other.functionSchema && + functionType == other.functionType && + origin == other.origin && + promptData == other.promptData && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + functionData, + name, + projectId, + slug, description, functionSchema, functionType, origin, promptData, - if (tags.size == 0) null else tags.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + tags, + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{functionData=$functionData, name=$name, projectId=$projectId, slug=$slug, description=$description, functionSchema=$functionSchema, functionType=$functionType, origin=$origin, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" } @JsonDeserialize(using = FunctionData.Deserializer::class) @@ -498,8 +1092,6 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun prompt(): Prompt? = prompt fun code(): Code? = code @@ -520,55 +1112,87 @@ constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { prompt != null -> visitor.visitPrompt(prompt) code != null -> visitor.visitCode(code) global != null -> visitor.visitGlobal(global) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): FunctionData = apply { - if (!validated) { - if (prompt == null && code == null && global == null) { - throw BraintrustInvalidDataException("Unknown FunctionData: $_json") - } - prompt?.validate() - code?.validate() - global?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) { + prompt.validate() + } + + override fun visitCode(code: Code) { + code.validate() + } + + override fun visitGlobal(global: Global) { + global.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) = prompt.validity() + + override fun visitCode(code: Code) = code.validity() + + override fun visitGlobal(global: Global) = global.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is FunctionData && - this.prompt == other.prompt && - this.code == other.code && - this.global == other.global + prompt == other.prompt && + code == other.code && + global == other.global } - override fun hashCode(): Int { - return Objects.hash( - prompt, - code, - global, - ) - } + override fun hashCode(): Int = Objects.hash(prompt, code, global) - override fun toString(): String { - return when { + override fun toString(): String = + when { prompt != null -> "FunctionData{prompt=$prompt}" code != null -> "FunctionData{code=$code}" global != null -> "FunctionData{global=$global}" _json != null -> "FunctionData{_unknown=$_json}" else -> throw IllegalStateException("Invalid FunctionData") } - } companion object { @@ -579,6 +1203,10 @@ constructor( fun ofGlobal(global: Global) = FunctionData(global = global) } + /** + * An interface that defines how to map each variant of [FunctionData] to a value of type + * [T]. + */ interface Visitor { fun visitPrompt(prompt: Prompt): T @@ -587,38 +1215,60 @@ constructor( fun visitGlobal(global: Global): T + /** + * Maps an unknown variant of [FunctionData] to a value of type [T]. + * + * An instance of [FunctionData] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown FunctionData: $json") } } - class Deserializer : BaseDeserializer(FunctionData::class) { + internal class Deserializer : BaseDeserializer(FunctionData::class) { override fun ObjectCodec.deserialize(node: JsonNode): FunctionData { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(prompt = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(code = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(global = it, _json = json) - } - return FunctionData(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(prompt = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(code = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(global = 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 -> FunctionData(_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() + } } } - class Serializer : BaseSerializer(FunctionData::class) { + internal class Serializer : BaseSerializer(FunctionData::class) { override fun serialize( value: FunctionData, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.prompt != null -> generator.writeObject(value.prompt) @@ -630,84 +1280,86 @@ constructor( } } - @JsonDeserialize(builder = Prompt.Builder::class) - @NoAutoDetect class Prompt + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of() + ) : this(type, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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 = additionalProperties - - fun validate(): Prompt = apply { - if (!validated) { - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Prompt && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(type, additionalProperties) - } - return hashCode - } - - override fun toString() = - "Prompt{type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Prompt]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Prompt]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(prompt: Prompt) = apply { - this.type = prompt.type - additionalProperties(prompt.additionalProperties) + type = prompt.type + additionalProperties = prompt.additionalProperties.toMutableMap() } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -715,159 +1367,314 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Prompt = Prompt(type, additionalProperties.toUnmodifiable()) - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns an immutable instance of [Prompt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Prompt = + Prompt(checkRequired("type", type), additionalProperties.toMutableMap()) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Type && this.value == other.value + fun validate(): Prompt = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() + type().validate() + validated = true + } - override fun toString() = value.toString() + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (type.asKnown()?.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 { - val PROMPT = Type(JsonField.of("prompt")) + val PROMPT = of("prompt") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - PROMPT, + PROMPT } + /** + * 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 { PROMPT, + /** + * 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) { PROMPT -> Value.PROMPT 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { PROMPT -> Known.PROMPT else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Code.Builder::class) - @NoAutoDetect - class Code - private constructor( - private val type: JsonField, - private val data: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun data(): Data = data.getRequired("data") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("data") @ExcludeMissing fun _data() = data + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Code = apply { - if (!validated) { - type() - data() - validated = true + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Prompt && + type == other.type && + additionalProperties == other.additionalProperties } - fun toBuilder() = Builder().from(this) + private val hashCode: Int by lazy { Objects.hash(type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Prompt{type=$type, additionalProperties=$additionalProperties}" + } + + class Code + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val data: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(data, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 BraintrustInvalidDataException 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 [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * 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 - return other is Code && - this.type == other.type && - this.data == other.data && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - data, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Code{type=$type, data=$data, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Code]. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Code]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var data: JsonField = JsonMissing.of() + private var data: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(code: Code) = apply { - this.type = code.type - this.data = code.data - additionalProperties(code.additionalProperties) + data = code.data + type = code.type + additionalProperties = code.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun data(data: Data) = data(JsonField.of(data)) - @JsonProperty("data") - @ExcludeMissing + /** + * 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.ofBundle(bundle)`. */ + fun data(bundle: Data.Bundle) = data(Data.ofBundle(bundle)) + + /** Alias for calling [data] with `Data.ofInline(inline)`. */ + fun data(inline: Data.Inline) = data(Data.ofInline(inline)) + + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -875,14 +1682,64 @@ constructor( 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 [Code]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Code = Code( - type, - data, - additionalProperties.toUnmodifiable(), + checkRequired("data", data), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Code = apply { + if (validated) { + return@apply + } + + data().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (data.asKnown()?.validity() ?: 0) + (type.asKnown()?.validity() ?: 0) + @JsonDeserialize(using = Data.Deserializer::class) @JsonSerialize(using = Data.Serializer::class) class Data @@ -892,8 +1749,6 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun bundle(): Bundle? = bundle fun inline(): Inline? = inline @@ -908,46 +1763,76 @@ constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { bundle != null -> visitor.visitBundle(bundle) inline != null -> visitor.visitInline(inline) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Data = apply { - if (!validated) { - if (bundle == null && inline == null) { - throw BraintrustInvalidDataException("Unknown Data: $_json") - } - inline?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) { + bundle.validate() + } + + override fun visitInline(inline: Inline) { + inline.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) = bundle.validity() + + override fun visitInline(inline: Inline) = inline.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Data && - this.bundle == other.bundle && - this.inline == other.inline + return other is Data && bundle == other.bundle && inline == other.inline } - override fun hashCode(): Int { - return Objects.hash(bundle, inline) - } + override fun hashCode(): Int = Objects.hash(bundle, inline) - override fun toString(): String { - return when { + override fun toString(): String = + when { bundle != null -> "Data{bundle=$bundle}" inline != null -> "Data{inline=$inline}" _json != null -> "Data{_unknown=$_json}" else -> throw IllegalStateException("Invalid Data") } - } companion object { @@ -956,39 +1841,68 @@ constructor( fun ofInline(inline: Inline) = Data(inline = inline) } + /** + * An interface that defines how to map each variant of [Data] to a value of type + * [T]. + */ interface Visitor { fun visitBundle(bundle: Bundle): T fun visitInline(inline: Inline): 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Data: $json") } } - class Deserializer : BaseDeserializer(Data::class) { + internal class Deserializer : BaseDeserializer(Data::class) { override fun ObjectCodec.deserialize(node: JsonNode): Data { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Data(bundle = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Data(inline = it, _json = json) - } - return Data(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Data(bundle = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Data(inline = 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() + } } } - class Serializer : BaseSerializer(Data::class) { + internal class Serializer : BaseSerializer(Data::class) { override fun serialize( value: Data, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.bundle != null -> generator.writeObject(value.bundle) @@ -999,474 +1913,840 @@ constructor( } } - @JsonDeserialize(builder = Bundle.Builder::class) - @NoAutoDetect class Bundle + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val runtimeContext: JsonField, - private val location: JsonField, private val bundleId: JsonField, + private val location: JsonField, + private val runtimeContext: JsonField, private val preview: JsonField, private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun runtimeContext(): RuntimeContext = - runtimeContext.getRequired("runtime_context") - - fun location(): Location = location.getRequired("location") - - fun bundleId(): String = bundleId.getRequired("bundle_id") - - /** A preview of the code */ - fun preview(): String? = preview.getNullable("preview") - - fun type(): Type = type.getRequired("type") + @JsonCreator + private constructor( + @JsonProperty("bundle_id") + @ExcludeMissing + bundleId: JsonField = JsonMissing.of(), + @JsonProperty("location") + @ExcludeMissing + location: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("preview") + @ExcludeMissing + preview: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(bundleId, location, runtimeContext, preview, type, mutableMapOf()) fun toCodeBundle(): CodeBundle = CodeBundle.builder() - .runtimeContext(runtimeContext) - .location(location) .bundleId(bundleId) + .location(location) + .runtimeContext(runtimeContext) .preview(preview) .build() - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + /** + * @throws BraintrustInvalidDataException 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 bundleId(): String = bundleId.getRequired("bundle_id") - @JsonProperty("location") @ExcludeMissing fun _location() = location + /** + * @throws BraintrustInvalidDataException 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 location(): CodeBundle.Location = location.getRequired("location") + + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): CodeBundle.RuntimeContext = + runtimeContext.getRequired("runtime_context") - @JsonProperty("bundle_id") @ExcludeMissing fun _bundleId() = bundleId + /** + * A preview of the code + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun preview(): String? = preview.getNullable("preview") - /** A preview of the code */ - @JsonProperty("preview") @ExcludeMissing fun _preview() = preview + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * Returns the raw JSON value of [bundleId]. + * + * Unlike [bundleId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("bundle_id") + @ExcludeMissing + fun _bundleId(): JsonField = bundleId + + /** + * 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 [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * Returns the raw JSON value of [preview]. + * + * Unlike [preview], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("preview") + @ExcludeMissing + fun _preview(): JsonField = preview + + /** + * 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 = additionalProperties - - fun validate(): Bundle = apply { - if (!validated) { - runtimeContext().validate() - location() - bundleId() - preview() - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Bundle && - this.runtimeContext == other.runtimeContext && - this.location == other.location && - this.bundleId == other.bundleId && - this.preview == other.preview && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtimeContext, - location, - bundleId, - preview, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Bundle{runtimeContext=$runtimeContext, location=$location, bundleId=$bundleId, preview=$preview, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Bundle]. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Bundle]. */ + class Builder internal constructor() { - private var runtimeContext: JsonField = JsonMissing.of() - private var location: JsonField = JsonMissing.of() - private var bundleId: JsonField = JsonMissing.of() + private var bundleId: JsonField? = null + private var location: JsonField? = null + private var runtimeContext: JsonField? = null private var preview: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(bundle: Bundle) = apply { - this.runtimeContext = bundle.runtimeContext - this.location = bundle.location - this.bundleId = bundle.bundleId - this.preview = bundle.preview - this.type = bundle.type - additionalProperties(bundle.additionalProperties) + bundleId = bundle.bundleId + location = bundle.location + runtimeContext = bundle.runtimeContext + preview = bundle.preview + type = bundle.type + additionalProperties = bundle.additionalProperties.toMutableMap() } - fun runtimeContext(runtimeContext: RuntimeContext) = - runtimeContext(JsonField.of(runtimeContext)) + fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - @JsonProperty("runtime_context") - @ExcludeMissing - fun runtimeContext(runtimeContext: JsonField) = apply { - this.runtimeContext = runtimeContext + /** + * Sets [Builder.bundleId] to an arbitrary JSON value. + * + * You should usually call [Builder.bundleId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun bundleId(bundleId: JsonField) = apply { + this.bundleId = bundleId } - fun location(location: Location) = location(JsonField.of(location)) - - @JsonProperty("location") - @ExcludeMissing - fun location(location: JsonField) = apply { + fun location(location: CodeBundle.Location) = + location(JsonField.of(location)) + + /** + * Sets [Builder.location] to an arbitrary JSON value. + * + * You should usually call [Builder.location] with a well-typed + * [CodeBundle.Location] 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 } - fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - - @JsonProperty("bundle_id") - @ExcludeMissing - fun bundleId(bundleId: JsonField) = apply { - this.bundleId = bundleId - } + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofExperiment(experiment)`. + */ + fun location(experiment: CodeBundle.Location.Experiment) = + location(CodeBundle.Location.ofExperiment(experiment)) + + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofFunction(function)`. + */ + fun location(function: CodeBundle.Location.Function) = + location(CodeBundle.Location.ofFunction(function)) + + fun runtimeContext(runtimeContext: CodeBundle.RuntimeContext) = + runtimeContext(JsonField.of(runtimeContext)) - /** A preview of the code */ - fun preview(preview: String) = preview(JsonField.of(preview)) + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [CodeBundle.RuntimeContext] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun runtimeContext(runtimeContext: JsonField) = + apply { + this.runtimeContext = runtimeContext + } /** A preview of the code */ - @JsonProperty("preview") - @ExcludeMissing + fun preview(preview: String?) = preview(JsonField.ofNullable(preview)) + + /** + * Sets [Builder.preview] to an arbitrary JSON value. + * + * You should usually call [Builder.preview] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun preview(preview: JsonField) = apply { this.preview = preview } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Bundle]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Bundle = Bundle( - runtimeContext, - location, - bundleId, + checkRequired("bundleId", bundleId), + checkRequired("location", location), + checkRequired("runtimeContext", runtimeContext), preview, - type, - additionalProperties.toUnmodifiable(), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Bundle = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + bundleId() + location().validate() + runtimeContext().validate() + preview() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (bundleId.asKnown() == null) 0 else 1) + + (location.asKnown()?.validity() ?: 0) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (if (preview.asKnown() == null) 0 else 1) + + (type.asKnown()?.validity() ?: 0) - override fun toString() = value.toString() + 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 { - val BUNDLE = Type(JsonField.of("bundle")) + val BUNDLE = of("bundle") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - BUNDLE, + BUNDLE } + /** + * 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 { BUNDLE, + /** + * 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) { BUNDLE -> Value.BUNDLE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { BUNDLE -> Known.BUNDLE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - - @JsonDeserialize(builder = Inline.Builder::class) - @NoAutoDetect - class Inline - private constructor( - private val type: JsonField, - private val runtimeContext: JsonField, - private val code: JsonField, - private val additionalProperties: Map, - ) { + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - private var validated: Boolean = false + private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Type = apply { + if (validated) { + return@apply + } - fun type(): Type = type.getRequired("type") + known() + validated = true + } - fun runtimeContext(): RuntimeContext = - runtimeContext.getRequired("runtime_context") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun code(): String = code.getRequired("code") + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + return other is Type && value == other.value + } - @JsonProperty("code") @ExcludeMissing fun _code() = code + override fun hashCode() = value.hashCode() - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun toString() = value.toString() + } - fun validate(): Inline = apply { - if (!validated) { - type() - runtimeContext().validate() - code() - validated = true + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Bundle && + bundleId == other.bundleId && + location == other.location && + runtimeContext == other.runtimeContext && + preview == other.preview && + type == other.type && + additionalProperties == other.additionalProperties } - fun toBuilder() = Builder().from(this) + private val hashCode: Int by lazy { + Objects.hash( + bundleId, + location, + runtimeContext, + preview, + type, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Bundle{bundleId=$bundleId, location=$location, runtimeContext=$runtimeContext, preview=$preview, type=$type, additionalProperties=$additionalProperties}" + } + + class Inline + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val code: JsonField, + private val runtimeContext: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("code") + @ExcludeMissing + code: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(code, runtimeContext, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 code(): String = code.getRequired("code") + + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): RuntimeContext = + runtimeContext.getRequired("runtime_context") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * @throws BraintrustInvalidDataException 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") - return other is Inline && - this.type == other.type && - this.runtimeContext == other.runtimeContext && - this.code == other.code && - this.additionalProperties == other.additionalProperties + /** + * Returns the raw JSON value of [code]. + * + * Unlike [code], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("code") @ExcludeMissing fun _code(): JsonField = code + + /** + * Returns the raw JSON value of [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * 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) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - runtimeContext, - code, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Inline{type=$type, runtimeContext=$runtimeContext, code=$code, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Inline]. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Inline]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var runtimeContext: JsonField = JsonMissing.of() - private var code: JsonField = JsonMissing.of() + private var code: JsonField? = null + private var runtimeContext: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inline: Inline) = apply { - this.type = inline.type - this.runtimeContext = inline.runtimeContext - this.code = inline.code - additionalProperties(inline.additionalProperties) + code = inline.code + runtimeContext = inline.runtimeContext + type = inline.type + additionalProperties = inline.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) + fun code(code: String) = code(JsonField.of(code)) - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } + /** + * Sets [Builder.code] to an arbitrary JSON value. + * + * You should usually call [Builder.code] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun code(code: JsonField) = apply { this.code = code } fun runtimeContext(runtimeContext: RuntimeContext) = runtimeContext(JsonField.of(runtimeContext)) - @JsonProperty("runtime_context") - @ExcludeMissing + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [RuntimeContext] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ fun runtimeContext(runtimeContext: JsonField) = apply { this.runtimeContext = runtimeContext } - fun code(code: String) = code(JsonField.of(code)) + fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("code") - @ExcludeMissing - fun code(code: JsonField) = apply { this.code = code } + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Inline]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Inline = Inline( - type, - runtimeContext, - code, - additionalProperties.toUnmodifiable(), + checkRequired("code", code), + checkRequired("runtimeContext", runtimeContext), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = RuntimeContext.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): Inline = apply { + if (validated) { + return@apply + } + + code() + runtimeContext().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (code.asKnown() == null) 0 else 1) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (type.asKnown()?.validity() ?: 0) + class RuntimeContext + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val runtime: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("runtime") + @ExcludeMissing + runtime: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(runtime, version, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 runtime(): Runtime = runtime.getRequired("runtime") + /** + * @throws BraintrustInvalidDataException 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 version(): String = version.getRequired("version") - @JsonProperty("runtime") @ExcludeMissing fun _runtime() = runtime + /** + * Returns the raw JSON value of [runtime]. + * + * Unlike [runtime], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime") + @ExcludeMissing + fun _runtime(): JsonField = runtime + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("version") + @ExcludeMissing + fun _version(): JsonField = version - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): RuntimeContext = apply { - if (!validated) { - runtime() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RuntimeContext && - this.runtime == other.runtime && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtime, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [RuntimeContext]. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RuntimeContext]. */ + class Builder internal constructor() { - private var runtime: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() + private var runtime: JsonField? = null + private var version: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(runtimeContext: RuntimeContext) = apply { - this.runtime = runtimeContext.runtime - this.version = runtimeContext.version - additionalProperties(runtimeContext.additionalProperties) + runtime = runtimeContext.runtime + version = runtimeContext.version + additionalProperties = + runtimeContext.additionalProperties.toMutableMap() } fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) - @JsonProperty("runtime") - @ExcludeMissing + /** + * Sets [Builder.runtime] to an arbitrary JSON value. + * + * You should usually call [Builder.runtime] with a well-typed [Runtime] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun runtime(runtime: JsonField) = apply { this.runtime = runtime } fun version(version: String) = version(JsonField.of(version)) - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } @@ -1474,67 +2754,136 @@ constructor( fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RuntimeContext]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RuntimeContext = RuntimeContext( - runtime, - version, - additionalProperties.toUnmodifiable(), + checkRequired("runtime", runtime), + checkRequired("version", version), + additionalProperties.toMutableMap(), ) } - class Runtime - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): RuntimeContext = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + runtime().validate() + version() + validated = true + } - return other is Runtime && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (runtime.asKnown()?.validity() ?: 0) + + (if (version.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Runtime + @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 { - val NODE = Runtime(JsonField.of("node")) + val NODE = of("node") - val PYTHON = Runtime(JsonField.of("python")) + val PYTHON = of("python") fun of(value: String) = Runtime(JsonField.of(value)) } + /** An enum containing [Runtime]'s known values. */ enum class Known { NODE, PYTHON, } + /** + * An enum containing [Runtime]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Runtime] 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 { NODE, PYTHON, + /** + * An enum member indicating that [Runtime] 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) { NODE -> Value.NODE @@ -1542,6 +2891,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value + * is a not a known member. + */ fun known(): Known = when (this) { NODE -> Known.NODE @@ -1552,214 +2910,482 @@ constructor( ) } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Runtime = apply { + if (validated) { + return@apply + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + 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 Runtime && 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 Type && this.value == other.value + return other is RuntimeContext && + runtime == other.runtime && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(runtime, version, additionalProperties) } - override fun hashCode() = value.hashCode() + override fun hashCode(): Int = hashCode - override fun toString() = value.toString() + override fun toString() = + "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + } + + 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 { - val INLINE = Type(JsonField.of("inline")) + val INLINE = of("inline") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - INLINE, + INLINE } + /** + * 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 { INLINE, + /** + * 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) { INLINE -> Value.INLINE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { INLINE -> Known.INLINE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + return other is Inline && + code == other.code && + runtimeContext == other.runtimeContext && + type == other.type && + additionalProperties == other.additionalProperties + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + private val hashCode: Int by lazy { + Objects.hash(code, runtimeContext, type, additionalProperties) } - return other is Type && this.value == other.value - } + override fun hashCode(): Int = hashCode - override fun hashCode() = value.hashCode() + override fun toString() = + "Inline{code=$code, runtimeContext=$runtimeContext, type=$type, additionalProperties=$additionalProperties}" + } + } - override fun toString() = value.toString() + 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 { - val CODE = Type(JsonField.of("code")) + val CODE = of("code") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - CODE, + CODE } + /** + * 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 { CODE, + /** + * 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) { CODE -> Value.CODE 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { CODE -> Known.CODE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Global.Builder::class) - @NoAutoDetect - class Global - private constructor( - private val type: JsonField, - private val name: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun name(): String = name.getRequired("name") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("name") @ExcludeMissing fun _name() = name + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Global = apply { - if (!validated) { - type() - name() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Global && - this.type == other.type && - this.name == other.name && - this.additionalProperties == other.additionalProperties + return other is Code && + data == other.data && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - name, - additionalProperties, - ) - } - return hashCode + private val hashCode: Int by lazy { Objects.hash(data, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Code{data=$data, type=$type, additionalProperties=$additionalProperties}" + } + + class Global + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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) } - override fun toString() = - "Global{type=$type, name=$name, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Global]. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Global]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var name: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(global: Global) = apply { - this.type = global.type - this.name = global.name - additionalProperties(global.additionalProperties) + name = global.name + type = global.type + additionalProperties = global.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1767,194 +3393,363 @@ constructor( 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 [Global]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Global = Global( - type, - name, - additionalProperties.toUnmodifiable(), + checkRequired("name", name), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Global = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val GLOBAL = Type(JsonField.of("global")) + val GLOBAL = of("global") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - GLOBAL, + GLOBAL } + /** + * 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 { GLOBAL, + /** + * 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) { GLOBAL -> Value.GLOBAL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { GLOBAL -> Known.GLOBAL else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Global && + name == other.name && + type == other.type && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(name, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Global{name=$name, type=$type, additionalProperties=$additionalProperties}" } } /** JSON schema for the function's parameters and return type */ - @JsonDeserialize(builder = FunctionSchema.Builder::class) - @NoAutoDetect class FunctionSchema + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val parameters: JsonValue?, - private val returns: JsonValue?, - private val additionalProperties: Map, + private val parameters: JsonValue, + private val returns: JsonValue, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("parameters") @ExcludeMissing parameters: JsonValue = JsonMissing.of(), + @JsonProperty("returns") @ExcludeMissing returns: JsonValue = JsonMissing.of(), + ) : this(parameters, returns, mutableMapOf()) + + @JsonProperty("parameters") @ExcludeMissing fun _parameters(): JsonValue = parameters - @JsonProperty("parameters") fun parameters(): JsonValue? = parameters + @JsonProperty("returns") @ExcludeMissing fun _returns(): JsonValue = returns - @JsonProperty("returns") fun returns(): JsonValue? = returns + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionSchema && - this.parameters == other.parameters && - this.returns == other.returns && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - parameters, - returns, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "FunctionSchema{parameters=$parameters, returns=$returns, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [FunctionSchema]. */ fun builder() = Builder() } - class Builder { + /** A builder for [FunctionSchema]. */ + class Builder internal constructor() { - private var parameters: JsonValue? = null - private var returns: JsonValue? = null + private var parameters: JsonValue = JsonMissing.of() + private var returns: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(functionSchema: FunctionSchema) = apply { - this.parameters = functionSchema.parameters - this.returns = functionSchema.returns - additionalProperties(functionSchema.additionalProperties) + parameters = functionSchema.parameters + returns = functionSchema.returns + additionalProperties = functionSchema.additionalProperties.toMutableMap() } - @JsonProperty("parameters") fun parameters(parameters: JsonValue) = apply { this.parameters = parameters } - @JsonProperty("returns") fun returns(returns: JsonValue) = apply { this.returns = returns } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FunctionSchema]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): FunctionSchema = - FunctionSchema( - parameters, - returns, - additionalProperties.toUnmodifiable(), - ) + FunctionSchema(parameters, returns, additionalProperties.toMutableMap()) } - } - class FunctionType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): FunctionSchema = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = 0 override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is FunctionType && this.value == other.value + return other is FunctionSchema && + parameters == other.parameters && + returns == other.returns && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash(parameters, returns, additionalProperties) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "FunctionSchema{parameters=$parameters, returns=$returns, additionalProperties=$additionalProperties}" + } + + class FunctionType @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 { - val LLM = FunctionType(JsonField.of("llm")) + val LLM = of("llm") - val SCORER = FunctionType(JsonField.of("scorer")) + val SCORER = of("scorer") - val TASK = FunctionType(JsonField.of("task")) + val TASK = of("task") - val TOOL = FunctionType(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = FunctionType(JsonField.of(value)) } + /** An enum containing [FunctionType]'s known values. */ enum class Known { LLM, SCORER, @@ -1962,14 +3757,33 @@ constructor( TOOL, } + /** + * An enum containing [FunctionType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [FunctionType] 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 { LLM, SCORER, TASK, TOOL, + /** + * An enum member indicating that [FunctionType] 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) { LLM -> Value.LLM @@ -1979,6 +3793,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { LLM -> Known.LLM @@ -1988,233 +3811,325 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown FunctionType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): FunctionType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FunctionType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } - @JsonDeserialize(builder = Origin.Builder::class) - @NoAutoDetect class Origin + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val objectType: ObjectType?, - private val objectId: String?, - private val internal_: Boolean?, - private val additionalProperties: Map, + private val objectId: JsonField, + private val objectType: JsonField, + private val internal_: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("internal") + @ExcludeMissing + internal_: JsonField = JsonMissing.of(), + ) : this(objectId, objectType, internal_, mutableMapOf()) - /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + /** + * Id of the object the function is originating from + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** Id of the object the function is originating from */ - @JsonProperty("object_id") fun objectId(): String? = objectId + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") /** * The function exists for internal purposes and should not be displayed in the list of * functions. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("internal") fun internal_(): Boolean? = internal_ + fun internal_(): Boolean? = internal_.getNullable("internal") - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [internal_]. + * + * Unlike [internal_], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("internal") @ExcludeMissing fun _internal_(): JsonField = internal_ - return other is Origin && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.internal_ == other.internal_ && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectType, - objectId, - internal_, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Origin{objectType=$objectType, objectId=$objectId, internal_=$internal_, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Origin]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Origin]. */ + class Builder internal constructor() { - private var objectType: ObjectType? = null - private var objectId: String? = null - private var internal_: Boolean? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var internal_: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(origin: Origin) = apply { - this.objectType = origin.objectType - this.objectId = origin.objectId - this.internal_ = origin.internal_ - additionalProperties(origin.additionalProperties) + objectId = origin.objectId + objectType = origin.objectType + internal_ = origin.internal_ + additionalProperties = origin.additionalProperties.toMutableMap() } + /** Id of the object the function is originating from */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) - /** Id of the object the function is originating from */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } /** * The function exists for internal purposes and should not be displayed in the list of * functions. */ - @JsonProperty("internal") - fun internal_(internal_: Boolean) = apply { this.internal_ = internal_ } + fun internal_(internal_: Boolean?) = internal_(JsonField.ofNullable(internal_)) + + /** + * Alias for [Builder.internal_]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun internal_(internal_: Boolean) = internal_(internal_ as Boolean?) + + /** + * Sets [Builder.internal_] to an arbitrary JSON value. + * + * You should usually call [Builder.internal_] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun internal_(internal_: JsonField) = apply { this.internal_ = internal_ } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Origin]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Origin = Origin( - checkNotNull(objectType) { "`objectType` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), internal_, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is ObjectType && this.value == other.value + fun validate(): Origin = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val EXPERIMENT = ObjectType(JsonField.of("experiment")) - - val DATASET = ObjectType(JsonField.of("dataset")) - - val PROMPT = ObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) - - val GROUP = ObjectType(JsonField.of("group")) - - val ROLE = ObjectType(JsonField.of("role")) - - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + objectId() + objectType().validate() + internal_() + validated = true + } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (internal_.asKnown() == null) 0 else 1) - fun of(value: String) = ObjectType(JsonField.of(value)) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + return other is Origin && + objectId == other.objectId && + objectType == other.objectType && + internal_ == other.internal_ && + additionalProperties == other.additionalProperties + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + private val hashCode: Int by lazy { + Objects.hash(objectId, objectType, internal_, additionalProperties) + } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + override fun hashCode(): Int = hashCode - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } + override fun toString() = + "Origin{objectId=$objectId, objectType=$objectType, internal_=$internal_, additionalProperties=$additionalProperties}" + } - fun asString(): String = _value().asStringOrThrow() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is FunctionCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "FunctionCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionDeleteParams.kt index d766ee5e..1e498c2e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a function object by its id */ class FunctionDeleteParams -constructor( - private val functionId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val functionId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun functionId(): String = functionId + /** Function id */ + fun functionId(): String? = functionId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> functionId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): FunctionDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FunctionDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [FunctionDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var functionId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(functionDeleteParams: FunctionDeleteParams) = apply { + functionId = functionDeleteParams.functionId + additionalHeaders = functionDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = functionDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = functionDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Function id */ + fun functionId(functionId: String?) = apply { this.functionId = functionId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is FunctionDeleteParams && - this.functionId == other.functionId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - functionId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "FunctionDeleteParams{functionId=$functionId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var functionId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(functionDeleteParams: FunctionDeleteParams) = apply { - this.functionId = functionDeleteParams.functionId - additionalQueryParams(functionDeleteParams.additionalQueryParams) - additionalHeaders(functionDeleteParams.additionalHeaders) - additionalBodyProperties(functionDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Function id */ - fun functionId(functionId: String) = apply { this.functionId = functionId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [FunctionDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): FunctionDeleteParams = FunctionDeleteParams( - checkNotNull(functionId) { "`functionId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + functionId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> functionId ?: "" + 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 FunctionDeleteParams && + functionId == other.functionId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(functionId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "FunctionDeleteParams{functionId=$functionId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeParams.kt index c036bd58..cd1a0906 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeParams.kt @@ -9,11 +9,15 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -25,391 +29,840 @@ 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 +/** Invoke a function. */ class FunctionInvokeParams -constructor( - private val functionId: String, - private val input: JsonValue?, - private val messages: List?, - private val mode: Mode?, - private val parent: Parent?, - private val stream: Boolean?, - private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun functionId(): String = functionId - - fun input(): JsonValue? = input - - fun messages(): List? = messages - - fun mode(): Mode? = mode - - fun parent(): Parent? = parent - - fun stream(): Boolean? = stream - - fun version(): String? = version - - internal fun getBody(): FunctionInvokeBody { - return FunctionInvokeBody( - input, - messages, - mode, - parent, - stream, - version, - additionalBodyProperties, - ) +private constructor( + private val functionId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Function id */ + fun functionId(): String? = functionId + + /** The expected output of the function */ + fun _expected(): JsonValue = body._expected() + + /** Argument to the function, which can be any JSON serializable value */ + fun _input(): JsonValue = body._input() + + /** + * If the function is an LLM, additional messages to pass along to it + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun messages(): List? = body.messages() + + /** + * Any relevant metadata + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = body.metadata() + + /** + * The mode format of the returned value (defaults to 'auto') + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun mode(): Mode? = body.mode() + + /** + * Options for tracing the function call + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun parent(): Parent? = body.parent() + + /** + * Whether to stream the response. If true, results will be returned in the Braintrust SSE + * format. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun stream(): Boolean? = body.stream() + + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun version(): String? = body.version() + + /** + * Returns the raw JSON value of [messages]. + * + * Unlike [messages], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _messages(): JsonField> = body._messages() + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _metadata(): JsonField = body._metadata() + + /** + * Returns the raw JSON value of [mode]. + * + * Unlike [mode], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _mode(): JsonField = body._mode() + + /** + * Returns the raw JSON value of [parent]. + * + * Unlike [parent], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _parent(): JsonField = body._parent() + + /** + * Returns the raw JSON value of [stream]. + * + * Unlike [stream], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _stream(): JsonField = body._stream() + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _version(): JsonField = body._version() + + 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 { + + fun none(): FunctionInvokeParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FunctionInvokeParams]. */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [FunctionInvokeParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var functionId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> functionId - else -> "" + internal fun from(functionInvokeParams: FunctionInvokeParams) = apply { + functionId = functionInvokeParams.functionId + body = functionInvokeParams.body.toBuilder() + additionalHeaders = functionInvokeParams.additionalHeaders.toBuilder() + additionalQueryParams = functionInvokeParams.additionalQueryParams.toBuilder() } - } - /** The request to invoke a function */ - @JsonDeserialize(builder = FunctionInvokeBody.Builder::class) - @NoAutoDetect - class FunctionInvokeBody - internal constructor( - private val input: JsonValue?, - private val messages: List?, - private val mode: Mode?, - private val parent: Parent?, - private val stream: Boolean?, - private val version: String?, - private val additionalProperties: Map, - ) { + /** Function id */ + fun functionId(functionId: String?) = apply { this.functionId = functionId } + + /** + * 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: + * - [expected] + * - [input] + * - [messages] + * - [metadata] + * - [mode] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } - private var hashCode: Int = 0 + /** The expected output of the function */ + fun expected(expected: JsonValue) = apply { body.expected(expected) } /** Argument to the function, which can be any JSON serializable value */ - @JsonProperty("input") fun input(): JsonValue? = input + fun input(input: JsonValue) = apply { body.input(input) } /** If the function is an LLM, additional messages to pass along to it */ - @JsonProperty("messages") fun messages(): List? = messages + fun messages(messages: List) = apply { body.messages(messages) } + + /** + * Sets [Builder.messages] to an arbitrary JSON value. + * + * You should usually call [Builder.messages] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun messages(messages: JsonField>) = apply { body.messages(messages) } + + /** + * Adds a single [Message] to [messages]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMessage(message: Message) = apply { body.addMessage(message) } + + /** Alias for calling [addMessage] with `Message.ofSystem(system)`. */ + fun addMessage(system: Message.System) = apply { body.addMessage(system) } + + /** Alias for calling [addMessage] with `Message.ofUser(user)`. */ + fun addMessage(user: Message.User) = apply { body.addMessage(user) } + + /** Alias for calling [addMessage] with `Message.ofAssistant(assistant)`. */ + fun addMessage(assistant: Message.Assistant) = apply { body.addMessage(assistant) } + + /** Alias for calling [addMessage] with `Message.ofTool(tool)`. */ + fun addMessage(tool: Message.Tool) = apply { body.addMessage(tool) } + + /** Alias for calling [addMessage] with `Message.ofFunction(function)`. */ + fun addMessage(function: Message.Function) = apply { body.addMessage(function) } + + /** Alias for calling [addMessage] with `Message.ofFallback(fallback)`. */ + fun addMessage(fallback: Message.Fallback) = apply { body.addMessage(fallback) } + + /** Any relevant metadata */ + fun metadata(metadata: Metadata?) = apply { body.metadata(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 { body.metadata(metadata) } /** The mode format of the returned value (defaults to 'auto') */ - @JsonProperty("mode") fun mode(): Mode? = mode + fun mode(mode: Mode?) = apply { body.mode(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 { body.mode(mode) } /** Options for tracing the function call */ - @JsonProperty("parent") fun parent(): Parent? = parent + fun parent(parent: Parent) = apply { body.parent(parent) } + + /** + * Sets [Builder.parent] to an arbitrary JSON value. + * + * You should usually call [Builder.parent] with a well-typed [Parent] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun parent(parent: JsonField) = apply { body.parent(parent) } + + /** Alias for calling [parent] with `Parent.ofSpanParentStruct(spanParentStruct)`. */ + fun parent(spanParentStruct: Parent.SpanParentStruct) = apply { + body.parent(spanParentStruct) + } + + /** Alias for calling [parent] with `Parent.ofString(string)`. */ + fun parent(string: String) = apply { body.parent(string) } /** * Whether to stream the response. If true, results will be returned in the Braintrust SSE * format. */ - @JsonProperty("stream") fun stream(): Boolean? = stream + fun stream(stream: Boolean?) = apply { body.stream(stream) } + + /** + * Alias for [Builder.stream]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun stream(stream: Boolean) = stream(stream as Boolean?) + + /** + * Sets [Builder.stream] to an arbitrary JSON value. + * + * You should usually call [Builder.stream] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun stream(stream: JsonField) = apply { body.stream(stream) } /** The version of the function */ - @JsonProperty("version") fun version(): String? = version + fun version(version: String) = apply { body.version(version) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun version(version: JsonField) = apply { body.version(version) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is FunctionInvokeBody && - this.input == other.input && - this.messages == other.messages && - this.mode == other.mode && - this.parent == other.parent && - this.stream == other.stream && - this.version == other.version && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - input, - messages, - mode, - parent, - stream, - version, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "FunctionInvokeBody{input=$input, messages=$messages, mode=$mode, parent=$parent, stream=$stream, version=$version, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var input: JsonValue? = null - private var messages: List? = null - private var mode: Mode? = null - private var parent: Parent? = null - private var stream: Boolean? = null - private var version: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(functionInvokeBody: FunctionInvokeBody) = apply { - this.input = functionInvokeBody.input - this.messages = functionInvokeBody.messages - this.mode = functionInvokeBody.mode - this.parent = functionInvokeBody.parent - this.stream = functionInvokeBody.stream - this.version = functionInvokeBody.version - additionalProperties(functionInvokeBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Argument to the function, which can be any JSON serializable value */ - @JsonProperty("input") fun input(input: JsonValue) = apply { this.input = input } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** If the function is an LLM, additional messages to pass along to it */ - @JsonProperty("messages") - fun messages(messages: List) = apply { this.messages = messages } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The mode format of the returned value (defaults to 'auto') */ - @JsonProperty("mode") fun mode(mode: Mode) = apply { this.mode = mode } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Options for tracing the function call */ - @JsonProperty("parent") fun parent(parent: Parent) = apply { this.parent = parent } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** - * Whether to stream the response. If true, results will be returned in the Braintrust - * SSE format. - */ - @JsonProperty("stream") fun stream(stream: Boolean) = apply { this.stream = stream } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** The version of the function */ - @JsonProperty("version") fun version(version: String) = apply { this.version = version } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): FunctionInvokeBody = - FunctionInvokeBody( - input, - messages?.toUnmodifiable(), - mode, - parent, - stream, - version, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is FunctionInvokeParams && - this.functionId == other.functionId && - this.input == other.input && - this.messages == other.messages && - this.mode == other.mode && - this.parent == other.parent && - this.stream == other.stream && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [FunctionInvokeParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): FunctionInvokeParams = + FunctionInvokeParams( + functionId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - functionId, - input, - messages, - mode, - parent, - stream, - version, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "FunctionInvokeParams{functionId=$functionId, input=$input, messages=$messages, mode=$mode, parent=$parent, stream=$stream, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun _pathParam(index: Int): String = + when (index) { + 0 -> functionId ?: "" + else -> "" + } - fun toBuilder() = Builder().from(this) + override fun _headers(): Headers = additionalHeaders - companion object { + override fun _queryParams(): QueryParams = additionalQueryParams - fun builder() = Builder() - } + /** The request to invoke a function */ + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val expected: JsonValue, + private val input: JsonValue, + private val messages: JsonField>, + private val metadata: JsonField, + private val mode: JsonField, + private val parent: JsonField, + private val stream: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { - @NoAutoDetect - class Builder { + @JsonCreator + private constructor( + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonValue = JsonMissing.of(), + @JsonProperty("messages") + @ExcludeMissing + messages: JsonField> = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("mode") @ExcludeMissing mode: JsonField = JsonMissing.of(), + @JsonProperty("parent") @ExcludeMissing parent: JsonField = JsonMissing.of(), + @JsonProperty("stream") @ExcludeMissing stream: JsonField = JsonMissing.of(), + @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of(), + ) : this(expected, input, messages, metadata, mode, parent, stream, version, mutableMapOf()) - private var functionId: String? = null - private var input: JsonValue? = null - private var messages: MutableList = mutableListOf() - private var mode: Mode? = null - private var parent: Parent? = null - private var stream: Boolean? = null - private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + /** The expected output of the function */ + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected - internal fun from(functionInvokeParams: FunctionInvokeParams) = apply { - this.functionId = functionInvokeParams.functionId - this.input = functionInvokeParams.input - this.messages(functionInvokeParams.messages ?: listOf()) - this.mode = functionInvokeParams.mode - this.parent = functionInvokeParams.parent - this.stream = functionInvokeParams.stream - this.version = functionInvokeParams.version - additionalQueryParams(functionInvokeParams.additionalQueryParams) - additionalHeaders(functionInvokeParams.additionalHeaders) - additionalBodyProperties(functionInvokeParams.additionalBodyProperties) - } + /** Argument to the function, which can be any JSON serializable value */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonValue = input - /** Function id */ - fun functionId(functionId: String) = apply { this.functionId = functionId } + /** + * If the function is an LLM, additional messages to pass along to it + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun messages(): List? = messages.getNullable("messages") - /** Argument to the function, which can be any JSON serializable value */ - fun input(input: JsonValue) = apply { this.input = input } + /** + * Any relevant metadata + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") - /** If the function is an LLM, additional messages to pass along to it */ - fun messages(messages: List) = apply { - this.messages.clear() - this.messages.addAll(messages) - } + /** + * The mode format of the returned value (defaults to 'auto') + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun mode(): Mode? = mode.getNullable("mode") - /** If the function is an LLM, additional messages to pass along to it */ - fun addMessage(message: Message) = apply { this.messages.add(message) } + /** + * Options for tracing the function call + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun parent(): Parent? = parent.getNullable("parent") - /** The mode format of the returned value (defaults to 'auto') */ - fun mode(mode: Mode) = apply { this.mode = mode } + /** + * Whether to stream the response. If true, results will be returned in the Braintrust SSE + * format. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun stream(): Boolean? = stream.getNullable("stream") - /** Options for tracing the function call */ - fun parent(parent: Parent) = apply { this.parent = parent } + /** + * The version of the function + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun version(): String? = version.getNullable("version") - /** Options for tracing the function call */ - fun parent(spanParentStruct: Parent.SpanParentStruct) = apply { - this.parent = Parent.ofSpanParentStruct(spanParentStruct) - } + /** + * Returns the raw JSON value of [messages]. + * + * Unlike [messages], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("messages") + @ExcludeMissing + fun _messages(): JsonField> = messages - /** Options for tracing the function call */ - fun parent(string: String) = apply { this.parent = Parent.ofString(string) } + /** + * 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 /** - * Whether to stream the response. If true, results will be returned in the Braintrust SSE - * format. + * Returns the raw JSON value of [mode]. + * + * Unlike [mode], this method doesn't throw if the JSON field has an unexpected type. */ - fun stream(stream: Boolean) = apply { this.stream = stream } + @JsonProperty("mode") @ExcludeMissing fun _mode(): JsonField = mode - /** The version of the function */ - fun version(version: String) = apply { this.version = version } + /** + * Returns the raw JSON value of [parent]. + * + * Unlike [parent], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("parent") @ExcludeMissing fun _parent(): JsonField = parent - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [stream]. + * + * Unlike [stream], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("stream") @ExcludeMissing fun _stream(): JsonField = stream - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun toBuilder() = Builder().from(this) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + companion object { - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var expected: JsonValue = JsonMissing.of() + private var input: JsonValue = JsonMissing.of() + private var messages: JsonField>? = null + private var metadata: JsonField = JsonMissing.of() + private var mode: JsonField = JsonMissing.of() + private var parent: JsonField = JsonMissing.of() + private var stream: JsonField = JsonMissing.of() + private var version: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + internal fun from(body: Body) = apply { + expected = body.expected + input = body.input + messages = body.messages.map { it.toMutableList() } + metadata = body.metadata + mode = body.mode + parent = body.parent + stream = body.stream + version = body.version + additionalProperties = body.additionalProperties.toMutableMap() + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** The expected output of the function */ + fun expected(expected: JsonValue) = apply { this.expected = expected } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Argument to the function, which can be any JSON serializable value */ + fun input(input: JsonValue) = apply { this.input = input } + + /** If the function is an LLM, additional messages to pass along to it */ + fun messages(messages: List) = messages(JsonField.of(messages)) + + /** + * Sets [Builder.messages] to an arbitrary JSON value. + * + * You should usually call [Builder.messages] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun messages(messages: JsonField>) = apply { + this.messages = messages.map { it.toMutableList() } + } + + /** + * Adds a single [Message] to [messages]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMessage(message: Message) = apply { + messages = + (messages ?: JsonField.of(mutableListOf())).also { + checkKnown("messages", it).add(message) + } + } + + /** Alias for calling [addMessage] with `Message.ofSystem(system)`. */ + fun addMessage(system: Message.System) = addMessage(Message.ofSystem(system)) + + /** Alias for calling [addMessage] with `Message.ofUser(user)`. */ + fun addMessage(user: Message.User) = addMessage(Message.ofUser(user)) + + /** Alias for calling [addMessage] with `Message.ofAssistant(assistant)`. */ + fun addMessage(assistant: Message.Assistant) = + addMessage(Message.ofAssistant(assistant)) + + /** Alias for calling [addMessage] with `Message.ofTool(tool)`. */ + fun addMessage(tool: Message.Tool) = addMessage(Message.ofTool(tool)) + + /** Alias for calling [addMessage] with `Message.ofFunction(function)`. */ + fun addMessage(function: Message.Function) = addMessage(Message.ofFunction(function)) + + /** Alias for calling [addMessage] with `Message.ofFallback(fallback)`. */ + fun addMessage(fallback: Message.Fallback) = addMessage(Message.ofFallback(fallback)) + + /** Any relevant metadata */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + + /** The mode format of the returned value (defaults to 'auto') */ + fun mode(mode: Mode?) = mode(JsonField.ofNullable(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 } + + /** Options for tracing the function call */ + fun parent(parent: Parent) = parent(JsonField.of(parent)) + + /** + * Sets [Builder.parent] to an arbitrary JSON value. + * + * You should usually call [Builder.parent] with a well-typed [Parent] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun parent(parent: JsonField) = apply { this.parent = parent } + + /** Alias for calling [parent] with `Parent.ofSpanParentStruct(spanParentStruct)`. */ + fun parent(spanParentStruct: Parent.SpanParentStruct) = + parent(Parent.ofSpanParentStruct(spanParentStruct)) + + /** Alias for calling [parent] with `Parent.ofString(string)`. */ + fun parent(string: String) = parent(Parent.ofString(string)) + + /** + * Whether to stream the response. If true, results will be returned in the Braintrust + * SSE format. + */ + fun stream(stream: Boolean?) = stream(JsonField.ofNullable(stream)) + + /** + * Alias for [Builder.stream]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun stream(stream: Boolean) = stream(stream as Boolean?) + + /** + * Sets [Builder.stream] to an arbitrary JSON value. + * + * You should usually call [Builder.stream] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun stream(stream: JsonField) = apply { this.stream = stream } + + /** The version of the function */ + fun version(version: String) = version(JsonField.of(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun version(version: JsonField) = apply { this.version = version } + + 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( + expected, + input, + (messages ?: JsonMissing.of()).map { it.toImmutable() }, + metadata, + mode, + parent, + stream, + version, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + messages()?.forEach { it.validate() } + metadata()?.validate() + mode()?.validate() + parent()?.validate() + stream() + version() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): FunctionInvokeParams = - FunctionInvokeParams( - checkNotNull(functionId) { "`functionId` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (messages.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (metadata.asKnown()?.validity() ?: 0) + + (mode.asKnown()?.validity() ?: 0) + + (parent.asKnown()?.validity() ?: 0) + + (if (stream.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + expected == other.expected && + input == other.input && + messages == other.messages && + metadata == other.metadata && + mode == other.mode && + parent == other.parent && + stream == other.stream && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + expected, input, - if (messages.size == 0) null else messages.toUnmodifiable(), + messages, + metadata, mode, parent, stream, version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{expected=$expected, input=$input, messages=$messages, metadata=$metadata, mode=$mode, parent=$parent, stream=$stream, version=$version, additionalProperties=$additionalProperties}" } @JsonDeserialize(using = Message.Deserializer::class) @@ -425,8 +878,6 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun system(): System? = system fun user(): User? = user @@ -465,8 +916,8 @@ constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { system != null -> visitor.visitSystem(system) user != null -> visitor.visitUser(user) assistant != null -> visitor.visitAssistant(assistant) @@ -475,57 +926,96 @@ constructor( fallback != null -> visitor.visitFallback(fallback) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Message = apply { - if (!validated) { - if ( - system == null && - user == null && - assistant == null && - tool == null && - function == null && - fallback == null - ) { - throw BraintrustInvalidDataException("Unknown Message: $_json") - } - system?.validate() - user?.validate() - assistant?.validate() - tool?.validate() - function?.validate() - fallback?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitSystem(system: System) { + system.validate() + } + + override fun visitUser(user: User) { + user.validate() + } + + override fun visitAssistant(assistant: Assistant) { + assistant.validate() + } + + override fun visitTool(tool: Tool) { + tool.validate() + } + + override fun visitFunction(function: Function) { + function.validate() + } + + override fun visitFallback(fallback: Fallback) { + fallback.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitSystem(system: System) = system.validity() + + override fun visitUser(user: User) = user.validity() + + override fun visitAssistant(assistant: Assistant) = assistant.validity() + + override fun visitTool(tool: Tool) = tool.validity() + + override fun visitFunction(function: Function) = function.validity() + + override fun visitFallback(fallback: Fallback) = fallback.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is Message && - this.system == other.system && - this.user == other.user && - this.assistant == other.assistant && - this.tool == other.tool && - this.function == other.function && - this.fallback == other.fallback + system == other.system && + user == other.user && + assistant == other.assistant && + tool == other.tool && + function == other.function && + fallback == other.fallback } - override fun hashCode(): Int { - return Objects.hash( - system, - user, - assistant, - tool, - function, - fallback, - ) - } + override fun hashCode(): Int = + Objects.hash(system, user, assistant, tool, function, fallback) - override fun toString(): String { - return when { + override fun toString(): String = + when { system != null -> "Message{system=$system}" user != null -> "Message{user=$user}" assistant != null -> "Message{assistant=$assistant}" @@ -535,7 +1025,6 @@ constructor( _json != null -> "Message{_unknown=$_json}" else -> throw IllegalStateException("Invalid Message") } - } companion object { @@ -552,6 +1041,9 @@ constructor( fun ofFallback(fallback: Fallback) = Message(fallback = fallback) } + /** + * An interface that defines how to map each variant of [Message] to a value of type [T]. + */ interface Visitor { fun visitSystem(system: System): T @@ -566,50 +1058,69 @@ constructor( fun visitFallback(fallback: Fallback): T + /** + * Maps an unknown variant of [Message] to a value of type [T]. + * + * An instance of [Message] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Message: $json") } } - class Deserializer : BaseDeserializer(Message::class) { + internal class Deserializer : BaseDeserializer(Message::class) { override fun ObjectCodec.deserialize(node: JsonNode): Message { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(system = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(user = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(assistant = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(tool = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(function = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(fallback = it, _json = json) - } - return Message(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Message(system = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(user = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(assistant = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(tool = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(function = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(fallback = 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 -> Message(_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() + } } } - class Serializer : BaseSerializer(Message::class) { + internal class Serializer : BaseSerializer(Message::class) { override fun serialize( value: Message, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.system != null -> generator.writeObject(value.system) @@ -624,120 +1135,144 @@ constructor( } } - @JsonDeserialize(builder = System.Builder::class) - @NoAutoDetect class System + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val content: JsonField, private val role: JsonField, + private val content: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(role, content, name, mutableMapOf()) - private var hashCode: Int = 0 + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun content(): String? = content.getNullable("content") - fun role(): Role = role.getRequired("role") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") - @JsonProperty("content") @ExcludeMissing fun _content() = content + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - @JsonProperty("role") @ExcludeMissing fun _role() = role + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): System = apply { - if (!validated) { - content() - role() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is System && - this.content == other.content && - this.role == other.role && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - role, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "System{content=$content, role=$role, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [System]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [System]. */ + class Builder internal constructor() { + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(system: System) = apply { - this.content = system.content - this.role = system.role - this.name = system.name - additionalProperties(system.additionalProperties) + role = system.role + content = system.content + name = system.name + additionalProperties = system.additionalProperties.toMutableMap() } - fun content(content: String) = content(JsonField.of(content)) - - @JsonProperty("content") - @ExcludeMissing - fun content(content: JsonField) = apply { this.content = content } - fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun role(role: JsonField) = apply { this.role = role } + fun content(content: String) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -745,181 +1280,357 @@ constructor( 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 [System]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): System = System( + checkRequired("role", role), content, - role, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): System = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content() + name() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + class Role @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 { - val SYSTEM = Role(JsonField.of("system")) + val SYSTEM = of("system") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - SYSTEM, + SYSTEM } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Role] 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, + /** + * An enum member indicating that [Role] 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 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { SYSTEM -> Known.SYSTEM else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Role && 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 System && + role == other.role && + content == other.content && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(role, content, name, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "System{role=$role, content=$content, name=$name, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = User.Builder::class) - @NoAutoDetect class User + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val content: JsonField, private val role: JsonField, + private val content: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(role, content, name, mutableMapOf()) - private var hashCode: Int = 0 + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun content(): Content? = content.getNullable("content") - fun role(): Role = role.getRequired("role") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") - @JsonProperty("content") @ExcludeMissing fun _content() = content + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - @JsonProperty("role") @ExcludeMissing fun _role() = role + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): User = apply { - if (!validated) { - content() - role() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is User && - this.content == other.content && - this.role == other.role && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - role, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "User{content=$content, role=$role, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [User]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [User]. */ + class Builder internal constructor() { + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(user: User) = apply { - this.content = user.content - this.role = user.role - this.name = user.name - additionalProperties(user.additionalProperties) + role = user.role + content = user.content + name = user.name + additionalProperties = user.additionalProperties.toMutableMap() } + fun role(role: Role) = role(JsonField.of(role)) + + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun role(role: JsonField) = apply { this.role = role } + fun content(content: Content) = content(JsonField.of(content)) - @JsonProperty("content") - @ExcludeMissing + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [Content] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun content(content: JsonField) = apply { this.content = content } - fun role(role: Role) = role(JsonField.of(role)) + /** Alias for calling [content] with `Content.ofText(text)`. */ + fun content(text: String) = content(Content.ofText(text)) - @JsonProperty("role") - @ExcludeMissing - fun role(role: JsonField) = apply { this.role = role } + /** Alias for calling [content] with `Content.ofArray(array)`. */ + fun contentOfArray(array: List) = + content(Content.ofArray(array)) fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -927,184 +1638,359 @@ constructor( 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 [User]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): User = User( + checkRequired("role", role), content, - role, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): User = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content()?.validate() + name() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (content.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + class Role @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 { - val USER = Role(JsonField.of("user")) + val USER = of("user") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - USER, + USER } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Role] 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 { USER, + /** + * An enum member indicating that [Role] 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) { USER -> Value.USER 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { USER -> Known.USER else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Role && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } @JsonDeserialize(using = Content.Deserializer::class) @JsonSerialize(using = Content.Serializer::class) class Content private constructor( - private val string: String? = null, - private val chatCompletionContentParts: List? = null, + private val text: String? = null, + private val array: List? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - - fun string(): String? = string + fun text(): String? = text - fun chatCompletionContentParts(): List? = - chatCompletionContentParts + fun array(): List? = array - fun isString(): Boolean = string != null + fun isText(): Boolean = text != null - fun isChatCompletionContentParts(): Boolean = chatCompletionContentParts != null + fun isArray(): Boolean = array != null - fun asString(): String = string.getOrThrow("string") + fun asText(): String = text.getOrThrow("text") - fun asChatCompletionContentParts(): List = - chatCompletionContentParts.getOrThrow("chatCompletionContentParts") + fun asArray(): List = array.getOrThrow("array") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - string != null -> visitor.visitString(string) - chatCompletionContentParts != null -> - visitor.visitChatCompletionContentParts(chatCompletionContentParts) + fun accept(visitor: Visitor): T = + when { + text != null -> visitor.visitText(text) + array != null -> visitor.visitArray(array) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Content = apply { - if (!validated) { - if (string == null && chatCompletionContentParts == null) { - throw BraintrustInvalidDataException("Unknown Content: $_json") - } - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitText(text: String) {} + + override fun visitArray(array: List) { + array.forEach { it.validate() } + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitText(text: String) = 1 + + override fun visitArray(array: List) = + array.sumOf { it.validity().toInt() } + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Content && - this.string == other.string && - this.chatCompletionContentParts == other.chatCompletionContentParts + return other is Content && text == other.text && array == other.array } - override fun hashCode(): Int { - return Objects.hash(string, chatCompletionContentParts) - } + override fun hashCode(): Int = Objects.hash(text, array) - override fun toString(): String { - return when { - string != null -> "Content{string=$string}" - chatCompletionContentParts != null -> - "Content{chatCompletionContentParts=$chatCompletionContentParts}" + override fun toString(): String = + when { + text != null -> "Content{text=$text}" + array != null -> "Content{array=$array}" _json != null -> "Content{_unknown=$_json}" else -> throw IllegalStateException("Invalid Content") } - } companion object { - fun ofString(string: String) = Content(string = string) + fun ofText(text: String) = Content(text = text) - fun ofChatCompletionContentParts( - chatCompletionContentParts: List - ) = Content(chatCompletionContentParts = chatCompletionContentParts) + fun ofArray(array: List) = + Content(array = array.toImmutable()) } + /** + * An interface that defines how to map each variant of [Content] to a value of type + * [T]. + */ interface Visitor { - fun visitString(string: String): T + fun visitText(text: String): T - fun visitChatCompletionContentParts( - chatCompletionContentParts: List - ): T + fun visitArray(array: List): T + /** + * Maps an unknown variant of [Content] to a value of type [T]. + * + * An instance of [Content] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Content: $json") } } - class Deserializer : BaseDeserializer(Content::class) { + internal class Deserializer : BaseDeserializer(Content::class) { override fun ObjectCodec.deserialize(node: JsonNode): Content { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Content(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>()) - ?.let { - return Content(chatCompletionContentParts = it, _json = json) - } - return Content(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Content(text = it, _json = json) + }, + tryDeserialize( + node, + jacksonTypeRef>(), + ) + ?.let { Content(array = 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 + // object). + 0 -> Content(_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() + } } } - class Serializer : BaseSerializer(Content::class) { + internal class Serializer : BaseSerializer(Content::class) { override fun serialize( value: Content, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.string != null -> generator.writeObject(value.string) - value.chatCompletionContentParts != null -> - generator.writeObject(value.chatCompletionContentParts) + value.text != null -> generator.writeObject(value.text) + value.array != null -> generator.writeObject(value.array) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Content") } @@ -1115,122 +2001,130 @@ constructor( @JsonSerialize(using = ChatCompletionContentPart.Serializer::class) class ChatCompletionContentPart private constructor( - private val chatCompletionContentPartText: ChatCompletionContentPartText? = - null, - private val chatCompletionContentPartImage: ChatCompletionContentPartImage? = - null, + private val text: ChatCompletionContentPartText? = null, + private val image: ChatCompletionContentPartImage? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - - fun chatCompletionContentPartText(): ChatCompletionContentPartText? = - chatCompletionContentPartText + fun text(): ChatCompletionContentPartText? = text - fun chatCompletionContentPartImage(): ChatCompletionContentPartImage? = - chatCompletionContentPartImage + fun image(): ChatCompletionContentPartImage? = image - fun isChatCompletionContentPartText(): Boolean = - chatCompletionContentPartText != null + fun isText(): Boolean = text != null - fun isChatCompletionContentPartImage(): Boolean = - chatCompletionContentPartImage != null + fun isImage(): Boolean = image != null - fun asChatCompletionContentPartText(): ChatCompletionContentPartText = - chatCompletionContentPartText.getOrThrow("chatCompletionContentPartText") + fun asText(): ChatCompletionContentPartText = text.getOrThrow("text") - fun asChatCompletionContentPartImage(): ChatCompletionContentPartImage = - chatCompletionContentPartImage.getOrThrow("chatCompletionContentPartImage") + fun asImage(): ChatCompletionContentPartImage = image.getOrThrow("image") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - chatCompletionContentPartText != null -> - visitor.visitChatCompletionContentPartText( - chatCompletionContentPartText - ) - chatCompletionContentPartImage != null -> - visitor.visitChatCompletionContentPartImage( - chatCompletionContentPartImage - ) + fun accept(visitor: Visitor): T = + when { + text != null -> visitor.visitText(text) + image != null -> visitor.visitImage(image) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): ChatCompletionContentPart = apply { - if (!validated) { - if ( - chatCompletionContentPartText == null && - chatCompletionContentPartImage == null - ) { - throw BraintrustInvalidDataException( - "Unknown ChatCompletionContentPart: $_json" - ) - } - chatCompletionContentPartText?.validate() - chatCompletionContentPartImage?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitText(text: ChatCompletionContentPartText) { + text.validate() + } + + override fun visitImage(image: ChatCompletionContentPartImage) { + image.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitText(text: ChatCompletionContentPartText) = + text.validity() + + override fun visitImage(image: ChatCompletionContentPartImage) = + image.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is ChatCompletionContentPart && - this.chatCompletionContentPartText == - other.chatCompletionContentPartText && - this.chatCompletionContentPartImage == - other.chatCompletionContentPartImage + text == other.text && + image == other.image } - override fun hashCode(): Int { - return Objects.hash( - chatCompletionContentPartText, - chatCompletionContentPartImage - ) - } + override fun hashCode(): Int = Objects.hash(text, image) - override fun toString(): String { - return when { - chatCompletionContentPartText != null -> - "ChatCompletionContentPart{chatCompletionContentPartText=$chatCompletionContentPartText}" - chatCompletionContentPartImage != null -> - "ChatCompletionContentPart{chatCompletionContentPartImage=$chatCompletionContentPartImage}" + override fun toString(): String = + when { + text != null -> "ChatCompletionContentPart{text=$text}" + image != null -> "ChatCompletionContentPart{image=$image}" _json != null -> "ChatCompletionContentPart{_unknown=$_json}" else -> throw IllegalStateException("Invalid ChatCompletionContentPart") } - } companion object { - fun ofChatCompletionContentPartText( - chatCompletionContentPartText: ChatCompletionContentPartText - ) = - ChatCompletionContentPart( - chatCompletionContentPartText = chatCompletionContentPartText - ) + fun ofText(text: ChatCompletionContentPartText) = + ChatCompletionContentPart(text = text) - fun ofChatCompletionContentPartImage( - chatCompletionContentPartImage: ChatCompletionContentPartImage - ) = - ChatCompletionContentPart( - chatCompletionContentPartImage = chatCompletionContentPartImage - ) + fun ofImage(image: ChatCompletionContentPartImage) = + ChatCompletionContentPart(image = image) } + /** + * An interface that defines how to map each variant of + * [ChatCompletionContentPart] to a value of type [T]. + */ interface Visitor { - fun visitChatCompletionContentPartText( - chatCompletionContentPartText: ChatCompletionContentPartText - ): T - - fun visitChatCompletionContentPartImage( - chatCompletionContentPartImage: ChatCompletionContentPartImage - ): T - + fun visitText(text: ChatCompletionContentPartText): T + + fun visitImage(image: ChatCompletionContentPartImage): T + + /** + * Maps an unknown variant of [ChatCompletionContentPart] to a value of type + * [T]. + * + * An instance of [ChatCompletionContentPart] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException( "Unknown ChatCompletionContentPart: $json" @@ -1238,7 +2132,7 @@ constructor( } } - class Deserializer : + internal class Deserializer : BaseDeserializer( ChatCompletionContentPart::class ) { @@ -1247,30 +2141,43 @@ constructor( node: JsonNode ): ChatCompletionContentPart { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { - it.validate() - } - ?.let { - return ChatCompletionContentPart( - chatCompletionContentPartText = it, - _json = json - ) - } - tryDeserialize(node, jacksonTypeRef()) { - it.validate() - } - ?.let { - return ChatCompletionContentPart( - chatCompletionContentPartImage = it, - _json = json - ) - } - return ChatCompletionContentPart(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize( + node, + jacksonTypeRef(), + ) + ?.let { + ChatCompletionContentPart(text = it, _json = json) + }, + tryDeserialize( + node, + jacksonTypeRef(), + ) + ?.let { + ChatCompletionContentPart(image = 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 -> ChatCompletionContentPart(_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() + } } } - class Serializer : + internal class Serializer : BaseSerializer( ChatCompletionContentPart::class ) { @@ -1278,13 +2185,11 @@ constructor( override fun serialize( value: ChatCompletionContentPart, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.chatCompletionContentPartText != null -> - generator.writeObject(value.chatCompletionContentPartText) - value.chatCompletionContentPartImage != null -> - generator.writeObject(value.chatCompletionContentPartImage) + value.text != null -> generator.writeObject(value.text) + value.image != null -> generator.writeObject(value.image) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid ChatCompletionContentPart") @@ -1293,162 +2198,252 @@ constructor( } } } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is User && + role == other.role && + content == other.content && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(role, content, name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "User{role=$role, content=$content, name=$name, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Assistant.Builder::class) - @NoAutoDetect class Assistant + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val role: JsonField, private val content: JsonField, private val functionCall: JsonField, private val name: JsonField, private val toolCalls: JsonField>, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("function_call") + @ExcludeMissing + functionCall: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("tool_calls") + @ExcludeMissing + toolCalls: JsonField> = JsonMissing.of(), + ) : this(role, content, functionCall, name, toolCalls, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun content(): String? = content.getNullable("content") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun functionCall(): FunctionCall? = functionCall.getNullable("function_call") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun toolCalls(): List? = toolCalls.getNullable("tool_calls") - @JsonProperty("role") @ExcludeMissing fun _role() = role - - @JsonProperty("content") @ExcludeMissing fun _content() = content + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - @JsonProperty("function_call") @ExcludeMissing fun _functionCall() = functionCall + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [functionCall]. + * + * Unlike [functionCall], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_call") + @ExcludeMissing + fun _functionCall(): JsonField = functionCall - @JsonProperty("tool_calls") @ExcludeMissing fun _toolCalls() = toolCalls + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonAnyGetter + /** + * Returns the raw JSON value of [toolCalls]. + * + * Unlike [toolCalls], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("tool_calls") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _toolCalls(): JsonField> = toolCalls - fun validate(): Assistant = apply { - if (!validated) { - role() - content() - functionCall()?.validate() - name() - toolCalls()?.forEach { it.validate() } - validated = true - } + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Assistant && - this.role == other.role && - this.content == other.content && - this.functionCall == other.functionCall && - this.name == other.name && - this.toolCalls == other.toolCalls && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - role, - content, - functionCall, - name, - toolCalls, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Assistant{role=$role, content=$content, functionCall=$functionCall, name=$name, toolCalls=$toolCalls, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Assistant]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Assistant]. */ + class Builder internal constructor() { - private var role: JsonField = JsonMissing.of() + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() private var functionCall: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() - private var toolCalls: JsonField> = - JsonMissing.of() + private var toolCalls: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(assistant: Assistant) = apply { - this.role = assistant.role - this.content = assistant.content - this.functionCall = assistant.functionCall - this.name = assistant.name - this.toolCalls = assistant.toolCalls - additionalProperties(assistant.additionalProperties) + role = assistant.role + content = assistant.content + functionCall = assistant.functionCall + name = assistant.name + toolCalls = assistant.toolCalls.map { it.toMutableList() } + additionalProperties = assistant.additionalProperties.toMutableMap() } fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun role(role: JsonField) = apply { this.role = role } - fun content(content: String) = content(JsonField.of(content)) + fun content(content: String?) = content(JsonField.ofNullable(content)) - @JsonProperty("content") - @ExcludeMissing + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun content(content: JsonField) = apply { this.content = content } - fun functionCall(functionCall: FunctionCall) = - functionCall(JsonField.of(functionCall)) + fun functionCall(functionCall: FunctionCall?) = + functionCall(JsonField.ofNullable(functionCall)) - @JsonProperty("function_call") - @ExcludeMissing + /** + * Sets [Builder.functionCall] to an arbitrary JSON value. + * + * You should usually call [Builder.functionCall] with a well-typed [FunctionCall] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ fun functionCall(functionCall: JsonField) = apply { this.functionCall = functionCall } - fun name(name: String) = name(JsonField.of(name)) + fun name(name: String?) = name(JsonField.ofNullable(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } - fun toolCalls(toolCalls: List) = - toolCalls(JsonField.of(toolCalls)) + fun toolCalls(toolCalls: List?) = + toolCalls(JsonField.ofNullable(toolCalls)) - @JsonProperty("tool_calls") - @ExcludeMissing + /** + * Sets [Builder.toolCalls] to an arbitrary JSON value. + * + * You should usually call [Builder.toolCalls] with a well-typed + * `List` value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ fun toolCalls(toolCalls: JsonField>) = apply { - this.toolCalls = toolCalls + this.toolCalls = toolCalls.map { it.toMutableList() } + } + + /** + * Adds a single [ChatCompletionMessageToolCall] to [toolCalls]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addToolCall(toolCall: ChatCompletionMessageToolCall) = apply { + toolCalls = + (toolCalls ?: JsonField.of(mutableListOf())).also { + checkKnown("toolCalls", it).add(toolCall) + } } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1456,301 +2451,570 @@ constructor( 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 [Assistant]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Assistant = Assistant( - role, + checkRequired("role", role), content, functionCall, name, - toolCalls.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + (toolCalls ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Assistant = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content() + functionCall()?.validate() + name() + toolCalls()?.forEach { it.validate() } + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) + + (functionCall.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (toolCalls.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + class Role @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 { - val ASSISTANT = Role(JsonField.of("assistant")) + val ASSISTANT = of("assistant") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - ASSISTANT, + ASSISTANT } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Role] 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 { ASSISTANT, + /** + * An enum member indicating that [Role] 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) { ASSISTANT -> Value.ASSISTANT 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { ASSISTANT -> Known.ASSISTANT else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Role && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } - @JsonDeserialize(builder = FunctionCall.Builder::class) - @NoAutoDetect class FunctionCall + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val arguments: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("arguments") + @ExcludeMissing + arguments: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(arguments, name, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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(): String = arguments.getRequired("arguments") + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - @JsonProperty("arguments") @ExcludeMissing fun _arguments() = arguments + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FunctionCall = apply { - if (!validated) { - arguments() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionCall && - this.arguments == other.arguments && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - arguments, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "FunctionCall{arguments=$arguments, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [FunctionCall]. + * + * The following fields are required: + * ```kotlin + * .arguments() + * .name() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FunctionCall]. */ + class Builder internal constructor() { - private var arguments: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var arguments: JsonField? = null + private var name: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(functionCall: FunctionCall) = apply { - this.arguments = functionCall.arguments - this.name = functionCall.name - additionalProperties(functionCall.additionalProperties) + arguments = functionCall.arguments + name = functionCall.name + additionalProperties = functionCall.additionalProperties.toMutableMap() } fun arguments(arguments: String) = arguments(JsonField.of(arguments)) - @JsonProperty("arguments") - @ExcludeMissing + /** + * Sets [Builder.arguments] to an arbitrary JSON value. + * + * You should usually call [Builder.arguments] with a well-typed [String] 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 } fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + 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 [FunctionCall]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .arguments() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionCall = + FunctionCall( + checkRequired("arguments", arguments), + checkRequired("name", name), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): FunctionCall = apply { + if (validated) { + return@apply + } + + arguments() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (arguments.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + return other is FunctionCall && + arguments == other.arguments && + name == other.name && + additionalProperties == other.additionalProperties + } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + private val hashCode: Int by lazy { + Objects.hash(arguments, name, additionalProperties) + } - fun build(): FunctionCall = - FunctionCall( - arguments, - name, - additionalProperties.toUnmodifiable(), - ) + override fun hashCode(): Int = hashCode + + override fun toString() = + "FunctionCall{arguments=$arguments, name=$name, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Assistant && + role == other.role && + content == other.content && + functionCall == other.functionCall && + name == other.name && + toolCalls == other.toolCalls && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(role, content, functionCall, name, toolCalls, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Assistant{role=$role, content=$content, functionCall=$functionCall, name=$name, toolCalls=$toolCalls, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Tool.Builder::class) - @NoAutoDetect class Tool + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val content: JsonField, private val role: JsonField, + private val content: JsonField, private val toolCallId: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("tool_call_id") + @ExcludeMissing + toolCallId: JsonField = JsonMissing.of(), + ) : this(role, content, toolCallId, mutableMapOf()) - private var hashCode: Int = 0 + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun content(): String? = content.getNullable("content") - fun role(): Role = role.getRequired("role") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun toolCallId(): String? = toolCallId.getNullable("tool_call_id") - @JsonProperty("content") @ExcludeMissing fun _content() = content - - @JsonProperty("role") @ExcludeMissing fun _role() = role + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - @JsonProperty("tool_call_id") @ExcludeMissing fun _toolCallId() = toolCallId + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - @JsonAnyGetter + /** + * Returns the raw JSON value of [toolCallId]. + * + * Unlike [toolCallId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("tool_call_id") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _toolCallId(): JsonField = toolCallId - fun validate(): Tool = apply { - if (!validated) { - content() - role() - toolCallId() - validated = true - } + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Tool && - this.content == other.content && - this.role == other.role && - this.toolCallId == other.toolCallId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - role, - toolCallId, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Tool{content=$content, role=$role, toolCallId=$toolCallId, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Tool]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Tool]. */ + class Builder internal constructor() { + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var toolCallId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(tool: Tool) = apply { - this.content = tool.content - this.role = tool.role - this.toolCallId = tool.toolCallId - additionalProperties(tool.additionalProperties) + role = tool.role + content = tool.content + toolCallId = tool.toolCallId + additionalProperties = tool.additionalProperties.toMutableMap() } - fun content(content: String) = content(JsonField.of(content)) - - @JsonProperty("content") - @ExcludeMissing - fun content(content: JsonField) = apply { this.content = content } - fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun role(role: JsonField) = apply { this.role = role } + fun content(content: String) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + fun toolCallId(toolCallId: String) = toolCallId(JsonField.of(toolCallId)) - @JsonProperty("tool_call_id") - @ExcludeMissing + /** + * Sets [Builder.toolCallId] to an arbitrary JSON value. + * + * You should usually call [Builder.toolCallId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun toolCallId(toolCallId: JsonField) = apply { this.toolCallId = toolCallId } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1758,181 +3022,352 @@ constructor( 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 [Tool]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Tool = Tool( + checkRequired("role", role), content, - role, toolCallId, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Tool = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content() + toolCallId() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) + + (if (toolCallId.asKnown() == null) 0 else 1) + + class Role @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 { - val TOOL = Role(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - TOOL, + TOOL } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Role] 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 { TOOL, + /** + * An enum member indicating that [Role] 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) { TOOL -> Value.TOOL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { TOOL -> Known.TOOL else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Role && 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 Tool && + role == other.role && + content == other.content && + toolCallId == other.toolCallId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(role, content, toolCallId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Tool{role=$role, content=$content, toolCallId=$toolCallId, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val content: JsonField, private val name: JsonField, private val role: JsonField, - private val additionalProperties: Map, + private val content: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun content(): String? = content.getNullable("content") + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + ) : this(name, role, content, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") - @JsonProperty("content") @ExcludeMissing fun _content() = content + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun content(): String? = content.getNullable("content") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - @JsonProperty("role") @ExcludeMissing fun _role() = role + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - content() - name() - role() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Function && - this.content == other.content && - this.name == other.name && - this.role == other.role && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - name, - role, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Function{content=$content, name=$name, role=$role, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Function]. + * + * The following fields are required: + * ```kotlin + * .name() + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Function]. */ + class Builder internal constructor() { + private var name: JsonField? = null + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(function: Function) = apply { - this.content = function.content - this.name = function.name - this.role = function.role - additionalProperties(function.additionalProperties) + name = function.name + role = function.role + content = function.content + additionalProperties = function.additionalProperties.toMutableMap() } - fun content(content: String) = content(JsonField.of(content)) - - @JsonProperty("content") - @ExcludeMissing - fun content(content: JsonField) = apply { this.content = content } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun role(role: JsonField) = apply { this.role = role } + fun content(content: String) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1940,165 +3375,323 @@ constructor( 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Function = Function( + checkRequired("name", name), + checkRequired("role", role), content, - name, - role, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Function = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + role().validate() + content() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) + + class Role @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 { - val FUNCTION = Role(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - FUNCTION, + FUNCTION } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Role] 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 { FUNCTION, + /** + * An enum member indicating that [Role] 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) { FUNCTION -> Value.FUNCTION 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { FUNCTION -> Known.FUNCTION else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Role && 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 Function && + name == other.name && + role == other.role && + content == other.content && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(name, role, content, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Function{name=$name, role=$role, content=$content, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Fallback.Builder::class) - @NoAutoDetect class Fallback + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val role: JsonField, private val content: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + ) : this(role, content, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun content(): String? = content.getNullable("content") - @JsonProperty("role") @ExcludeMissing fun _role() = role + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - @JsonProperty("content") @ExcludeMissing fun _content() = content + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Fallback = apply { - if (!validated) { - role() - content() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Fallback && - this.role == other.role && - this.content == other.content && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - role, - content, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Fallback{role=$role, content=$content, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Fallback]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Fallback]. */ + class Builder internal constructor() { - private var role: JsonField = JsonMissing.of() + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(fallback: Fallback) = apply { - this.role = fallback.role - this.content = fallback.content - additionalProperties(fallback.additionalProperties) + role = fallback.role + content = fallback.content + additionalProperties = fallback.additionalProperties.toMutableMap() } fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun role(role: JsonField) = apply { this.role = role } - fun content(content: String) = content(JsonField.of(content)) + fun content(content: String?) = content(JsonField.ofNullable(content)) - @JsonProperty("content") - @ExcludeMissing + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun content(content: JsonField) = apply { this.content = content } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2106,107 +3699,355 @@ constructor( 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 [Fallback]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Fallback = Fallback( - role, + checkRequired("role", role), content, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Fallback = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + (if (content.asKnown() == null) 0 else 1) + + class Role @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 { - val MODEL = Role(JsonField.of("model")) + val MODEL = of("model") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - MODEL, + MODEL } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Role] 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 { MODEL, + /** + * An enum member indicating that [Role] 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) { MODEL -> Value.MODEL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { MODEL -> Known.MODEL else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Role && 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 Fallback && + role == other.role && + content == other.content && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(role, content, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Fallback{role=$role, content=$content, additionalProperties=$additionalProperties}" } } - class Mode + /** Any relevant metadata */ + class Metadata @JsonCreator private constructor( - private val value: JsonField, - ) : Enum { + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Metadata]. */ + fun builder() = Builder() + } + + /** A builder for [Metadata]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Mode && this.value == other.value + return other is Metadata && additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + } + + /** The mode format of the returned value (defaults to 'auto') */ + 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 { - val AUTO = Mode(JsonField.of("auto")) + val AUTO = of("auto") - val PARALLEL = Mode(JsonField.of("parallel")) + val PARALLEL = of("parallel") fun of(value: String) = Mode(JsonField.of(value)) } + /** An enum containing [Mode]'s known values. */ enum class Known { AUTO, PARALLEL, } + /** + * 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 { AUTO, PARALLEL, + /** 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) { AUTO -> Value.AUTO @@ -2214,6 +4055,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { AUTO -> Known.AUTO @@ -2221,9 +4071,59 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown Mode: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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() } + /** Options for tracing the function call */ @JsonDeserialize(using = Parent.Deserializer::class) @JsonSerialize(using = Parent.Serializer::class) class Parent @@ -2233,10 +4133,9 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - /** Span parent properties */ fun spanParentStruct(): SpanParentStruct? = spanParentStruct + /** The parent's span identifier, created by calling `.export()` on a span */ fun string(): String? = string @@ -2244,94 +4143,156 @@ constructor( fun isString(): Boolean = string != null + /** Span parent properties */ fun asSpanParentStruct(): SpanParentStruct = spanParentStruct.getOrThrow("spanParentStruct") + /** The parent's span identifier, created by calling `.export()` on a span */ fun asString(): String = string.getOrThrow("string") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { spanParentStruct != null -> visitor.visitSpanParentStruct(spanParentStruct) string != null -> visitor.visitString(string) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Parent = apply { - if (!validated) { - if (spanParentStruct == null && string == null) { - throw BraintrustInvalidDataException("Unknown Parent: $_json") - } - spanParentStruct?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitSpanParentStruct(spanParentStruct: SpanParentStruct) { + spanParentStruct.validate() + } + + override fun visitString(string: String) {} + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitSpanParentStruct(spanParentStruct: SpanParentStruct) = + spanParentStruct.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 Parent && - this.spanParentStruct == other.spanParentStruct && - this.string == other.string + spanParentStruct == other.spanParentStruct && + string == other.string } - override fun hashCode(): Int { - return Objects.hash(spanParentStruct, string) - } + override fun hashCode(): Int = Objects.hash(spanParentStruct, string) - override fun toString(): String { - return when { + override fun toString(): String = + when { spanParentStruct != null -> "Parent{spanParentStruct=$spanParentStruct}" string != null -> "Parent{string=$string}" _json != null -> "Parent{_unknown=$_json}" else -> throw IllegalStateException("Invalid Parent") } - } companion object { + /** Span parent properties */ fun ofSpanParentStruct(spanParentStruct: SpanParentStruct) = Parent(spanParentStruct = spanParentStruct) + /** The parent's span identifier, created by calling `.export()` on a span */ fun ofString(string: String) = Parent(string = string) } + /** An interface that defines how to map each variant of [Parent] to a value of type [T]. */ interface Visitor { + /** Span parent properties */ fun visitSpanParentStruct(spanParentStruct: SpanParentStruct): T + /** The parent's span identifier, created by calling `.export()` on a span */ fun visitString(string: String): T + /** + * Maps an unknown variant of [Parent] to a value of type [T]. + * + * An instance of [Parent] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Parent: $json") } } - class Deserializer : BaseDeserializer(Parent::class) { + internal class Deserializer : BaseDeserializer(Parent::class) { override fun ObjectCodec.deserialize(node: JsonNode): Parent { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Parent(spanParentStruct = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef())?.let { - return Parent(string = it, _json = json) - } - return Parent(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Parent(spanParentStruct = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Parent(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 -> Parent(_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() + } } } - class Serializer : BaseSerializer(Parent::class) { + internal class Serializer : BaseSerializer(Parent::class) { override fun serialize( value: Parent, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.spanParentStruct != null -> generator.writeObject(value.spanParentStruct) @@ -2343,156 +4304,202 @@ constructor( } /** Span parent properties */ - @JsonDeserialize(builder = SpanParentStruct.Builder::class) - @NoAutoDetect class SpanParentStruct + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val objectType: JsonField, private val objectId: JsonField, - private val rowIds: JsonField, + private val objectType: JsonField, private val propagatedEvent: JsonField, - private val additionalProperties: Map, + private val rowIds: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun objectType(): ObjectType = objectType.getRequired("object_type") + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("propagated_event") + @ExcludeMissing + propagatedEvent: JsonField = JsonMissing.of(), + @JsonProperty("row_ids") + @ExcludeMissing + rowIds: JsonField = JsonMissing.of(), + ) : this(objectId, objectType, propagatedEvent, rowIds, mutableMapOf()) - /** The id of the container object you are logging to */ + /** + * The id of the container object you are logging to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** Identifiers for the row to to log a subspan under */ - fun rowIds(): RowIds? = rowIds.getNullable("row_ids") + /** + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = objectType.getRequired("object_type") - /** Include these properties in every span created under this parent */ + /** + * Include these properties in every span created under this parent + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun propagatedEvent(): PropagatedEvent? = propagatedEvent.getNullable("propagated_event") - @JsonProperty("object_type") @ExcludeMissing fun _objectType() = objectType + /** + * Identifiers for the row to to log a subspan under + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun rowIds(): RowIds? = rowIds.getNullable("row_ids") - /** The id of the container object you are logging to */ - @JsonProperty("object_id") @ExcludeMissing fun _objectId() = objectId + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - /** Identifiers for the row to to log a subspan under */ - @JsonProperty("row_ids") @ExcludeMissing fun _rowIds() = rowIds + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType - /** Include these properties in every span created under this parent */ + /** + * Returns the raw JSON value of [propagatedEvent]. + * + * Unlike [propagatedEvent], this method doesn't throw if the JSON field has an + * unexpected type. + */ @JsonProperty("propagated_event") @ExcludeMissing - fun _propagatedEvent() = propagatedEvent + fun _propagatedEvent(): JsonField = propagatedEvent - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Returns the raw JSON value of [rowIds]. + * + * Unlike [rowIds], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("row_ids") @ExcludeMissing fun _rowIds(): JsonField = rowIds - fun validate(): SpanParentStruct = apply { - if (!validated) { - objectType() - objectId() - rowIds()?.validate() - propagatedEvent()?.validate() - validated = true - } + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SpanParentStruct && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.rowIds == other.rowIds && - this.propagatedEvent == other.propagatedEvent && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectType, - objectId, - rowIds, - propagatedEvent, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "SpanParentStruct{objectType=$objectType, objectId=$objectId, rowIds=$rowIds, propagatedEvent=$propagatedEvent, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [SpanParentStruct]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [SpanParentStruct]. */ + class Builder internal constructor() { - private var objectType: JsonField = JsonMissing.of() - private var objectId: JsonField = JsonMissing.of() - private var rowIds: JsonField = JsonMissing.of() + private var objectId: JsonField? = null + private var objectType: JsonField? = null private var propagatedEvent: JsonField = JsonMissing.of() + private var rowIds: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(spanParentStruct: SpanParentStruct) = apply { - this.objectType = spanParentStruct.objectType - this.objectId = spanParentStruct.objectId - this.rowIds = spanParentStruct.rowIds - this.propagatedEvent = spanParentStruct.propagatedEvent - additionalProperties(spanParentStruct.additionalProperties) - } - - fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) - - @JsonProperty("object_type") - @ExcludeMissing - fun objectType(objectType: JsonField) = apply { - this.objectType = objectType + objectId = spanParentStruct.objectId + objectType = spanParentStruct.objectType + propagatedEvent = spanParentStruct.propagatedEvent + rowIds = spanParentStruct.rowIds + additionalProperties = spanParentStruct.additionalProperties.toMutableMap() } /** The id of the container object you are logging to */ fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - /** The id of the container object you are logging to */ - @JsonProperty("object_id") - @ExcludeMissing + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - /** Identifiers for the row to to log a subspan under */ - fun rowIds(rowIds: RowIds) = rowIds(JsonField.of(rowIds)) - - /** Identifiers for the row to to log a subspan under */ - @JsonProperty("row_ids") - @ExcludeMissing - fun rowIds(rowIds: JsonField) = apply { this.rowIds = rowIds } + fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) - /** Include these properties in every span created under this parent */ - fun propagatedEvent(propagatedEvent: PropagatedEvent) = - propagatedEvent(JsonField.of(propagatedEvent)) + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } /** Include these properties in every span created under this parent */ - @JsonProperty("propagated_event") - @ExcludeMissing + fun propagatedEvent(propagatedEvent: PropagatedEvent?) = + propagatedEvent(JsonField.ofNullable(propagatedEvent)) + + /** + * Sets [Builder.propagatedEvent] to an arbitrary JSON value. + * + * You should usually call [Builder.propagatedEvent] with a well-typed + * [PropagatedEvent] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ fun propagatedEvent(propagatedEvent: JsonField) = apply { this.propagatedEvent = propagatedEvent } + /** Identifiers for the row to to log a subspan under */ + fun rowIds(rowIds: RowIds?) = rowIds(JsonField.ofNullable(rowIds)) + + /** + * Sets [Builder.rowIds] to an arbitrary JSON value. + * + * You should usually call [Builder.rowIds] with a well-typed [RowIds] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun rowIds(rowIds: JsonField) = apply { this.rowIds = rowIds } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2500,137 +4507,246 @@ constructor( 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 [SpanParentStruct]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): SpanParentStruct = SpanParentStruct( - objectType, - objectId, - rowIds, + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), propagatedEvent, - additionalProperties.toUnmodifiable(), + rowIds, + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): SpanParentStruct = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + objectId() + objectType().validate() + propagatedEvent()?.validate() + rowIds()?.validate() + validated = true + } - return other is ObjectType && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (propagatedEvent.asKnown()?.validity() ?: 0) + + (rowIds.asKnown()?.validity() ?: 0) - override fun toString() = value.toString() + class ObjectType + @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 { - val PROJECT_LOGS = ObjectType(JsonField.of("project_logs")) + val PROJECT_LOGS = of("project_logs") + + val EXPERIMENT = of("experiment") - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + val PLAYGROUND_LOGS = of("playground_logs") fun of(value: String) = ObjectType(JsonField.of(value)) } + /** An enum containing [ObjectType]'s known values. */ enum class Known { PROJECT_LOGS, EXPERIMENT, + PLAYGROUND_LOGS, } + /** + * An enum containing [ObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ObjectType] 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 { PROJECT_LOGS, EXPERIMENT, + PLAYGROUND_LOGS, + /** + * An enum member indicating that [ObjectType] 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) { PROJECT_LOGS -> Value.PROJECT_LOGS EXPERIMENT -> Value.EXPERIMENT + PLAYGROUND_LOGS -> Value.PLAYGROUND_LOGS 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { PROJECT_LOGS -> Known.PROJECT_LOGS EXPERIMENT -> Known.EXPERIMENT + PLAYGROUND_LOGS -> Known.PLAYGROUND_LOGS else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") } - fun asString(): String = _value().asStringOrThrow() - } - - /** Include these properties in every span created under this parent */ - @JsonDeserialize(builder = PropagatedEvent.Builder::class) - @NoAutoDetect - class PropagatedEvent - private constructor( - private val additionalProperties: Map, - ) { + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): ObjectType = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + known() + validated = true + } - fun validate(): PropagatedEvent = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 PropagatedEvent && - this.additionalProperties == other.additionalProperties + return other is ObjectType && value == other.value } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + override fun hashCode() = value.hashCode() - override fun toString() = - "PropagatedEvent{additionalProperties=$additionalProperties}" + override fun toString() = value.toString() + } + + /** Include these properties in every span created under this parent */ + class PropagatedEvent + @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 [PropagatedEvent]. + */ fun builder() = Builder() } - class Builder { + /** A builder for [PropagatedEvent]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(propagatedEvent: PropagatedEvent) = apply { - additionalProperties(propagatedEvent.additionalProperties) + additionalProperties = propagatedEvent.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2638,140 +4754,229 @@ constructor( 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 [PropagatedEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): PropagatedEvent = - PropagatedEvent(additionalProperties.toUnmodifiable()) + PropagatedEvent(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): PropagatedEvent = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 PropagatedEvent && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PropagatedEvent{additionalProperties=$additionalProperties}" } /** Identifiers for the row to to log a subspan under */ - @JsonDeserialize(builder = RowIds.Builder::class) - @NoAutoDetect class RowIds + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val spanId: JsonField, private val rootSpanId: JsonField, - private val additionalProperties: Map, + private val spanId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The id of the row */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("span_id") + @ExcludeMissing + spanId: JsonField = JsonMissing.of(), + ) : this(id, rootSpanId, spanId, mutableMapOf()) + + /** + * The id of the row + * + * @throws BraintrustInvalidDataException 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") - /** The span_id of the row */ - fun spanId(): String = spanId.getRequired("span_id") - - /** The root_span_id of the row */ + /** + * The root_span_id of the row + * + * @throws BraintrustInvalidDataException 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 rootSpanId(): String = rootSpanId.getRequired("root_span_id") - /** The id of the row */ - @JsonProperty("id") @ExcludeMissing fun _id() = id + /** + * The span_id of the row + * + * @throws BraintrustInvalidDataException 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 spanId(): String = spanId.getRequired("span_id") + + /** + * 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 [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("root_span_id") + @ExcludeMissing + fun _rootSpanId(): JsonField = rootSpanId - /** The span_id of the row */ - @JsonProperty("span_id") @ExcludeMissing fun _spanId() = spanId + /** + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId - /** The root_span_id of the row */ - @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId() = rootSpanId + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): RowIds = apply { - if (!validated) { - id() - spanId() - rootSpanId() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RowIds && - this.id == other.id && - this.spanId == other.spanId && - this.rootSpanId == other.rootSpanId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - spanId, - rootSpanId, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "RowIds{id=$id, spanId=$spanId, rootSpanId=$rootSpanId, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [RowIds]. + * + * The following fields are required: + * ```kotlin + * .id() + * .rootSpanId() + * .spanId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RowIds]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var spanId: JsonField = JsonMissing.of() - private var rootSpanId: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var rootSpanId: JsonField? = null + private var spanId: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(rowIds: RowIds) = apply { - this.id = rowIds.id - this.spanId = rowIds.spanId - this.rootSpanId = rowIds.rootSpanId - additionalProperties(rowIds.additionalProperties) + id = rowIds.id + rootSpanId = rowIds.rootSpanId + spanId = rowIds.spanId + additionalProperties = rowIds.additionalProperties.toMutableMap() } /** The id of the row */ fun id(id: String) = id(JsonField.of(id)) - /** The id of the row */ - @JsonProperty("id") - @ExcludeMissing + /** + * 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 } - /** The span_id of the row */ - fun spanId(spanId: String) = spanId(JsonField.of(spanId)) - - /** The span_id of the row */ - @JsonProperty("span_id") - @ExcludeMissing - fun spanId(spanId: JsonField) = apply { this.spanId = spanId } - /** The root_span_id of the row */ fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) - /** The root_span_id of the row */ - @JsonProperty("root_span_id") - @ExcludeMissing + /** + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + /** The span_id of the row */ + fun spanId(spanId: String) = spanId(JsonField.of(spanId)) + + /** + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2779,15 +4984,130 @@ constructor( 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 [RowIds]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .rootSpanId() + * .spanId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RowIds = RowIds( - id, - spanId, - rootSpanId, - additionalProperties.toUnmodifiable(), + checkRequired("id", id), + checkRequired("rootSpanId", rootSpanId), + checkRequired("spanId", spanId), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): RowIds = apply { + if (validated) { + return@apply + } + + id() + rootSpanId() + spanId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (if (spanId.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RowIds && + id == other.id && + rootSpanId == other.rootSpanId && + spanId == other.spanId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, rootSpanId, spanId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RowIds{id=$id, rootSpanId=$rootSpanId, spanId=$spanId, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanParentStruct && + objectId == other.objectId && + objectType == other.objectType && + propagatedEvent == other.propagatedEvent && + rowIds == other.rowIds && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { + Objects.hash(objectId, objectType, propagatedEvent, rowIds, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SpanParentStruct{objectId=$objectId, objectType=$objectType, propagatedEvent=$propagatedEvent, rowIds=$rowIds, additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is FunctionInvokeParams && + functionId == other.functionId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(functionId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "FunctionInvokeParams{functionId=$functionId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeResponse.kt index 47762f1f..2250d99c 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionInvokeResponse.kt @@ -4,82 +4,110 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = FunctionInvokeResponse.Builder::class) -@NoAutoDetect class FunctionInvokeResponse -private constructor( - private val additionalProperties: Map, -) { +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor(private val additionalProperties: MutableMap) { - private var validated: Boolean = false + @JsonCreator private constructor() : this(mutableMapOf()) - private var hashCode: Int = 0 + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FunctionInvokeResponse = apply { - if (!validated) { - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionInvokeResponse && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "FunctionInvokeResponse{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [FunctionInvokeResponse]. */ fun builder() = Builder() } - class Builder { + /** A builder for [FunctionInvokeResponse]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(functionInvokeResponse: FunctionInvokeResponse) = apply { - additionalProperties(functionInvokeResponse.additionalProperties) + additionalProperties = functionInvokeResponse.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FunctionInvokeResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): FunctionInvokeResponse = - FunctionInvokeResponse(additionalProperties.toUnmodifiable()) + FunctionInvokeResponse(additionalProperties.toMutableMap()) } + + private var validated: Boolean = false + + fun validate(): FunctionInvokeResponse = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FunctionInvokeResponse && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "FunctionInvokeResponse{additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPage.kt index a61dab86..1a30d83b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPage.kt @@ -2,172 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.FunctionService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see FunctionService.list */ class FunctionListPage private constructor( - private val functionsService: FunctionService, + private val service: FunctionService, private val params: FunctionListParams, - private val response: Response, -) { + private val response: FunctionListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [FunctionListPageResponse], but gracefully handles missing data. + * + * @see FunctionListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionListPage && - this.functionsService == other.functionsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - functionsService, - params, - response, - ) - } - - override fun toString() = - "FunctionListPage{functionsService=$functionsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): FunctionListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - FunctionListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): FunctionListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - FunctionListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): FunctionListPage? { - return getNextPageParams()?.let { functionsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(functionsService: FunctionService, params: FunctionListParams, response: Response) = - FunctionListPage( - functionsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): FunctionListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): FunctionListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): FunctionListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [FunctionListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [FunctionListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: FunctionService? = null + private var params: FunctionListParams? = null + private var response: FunctionListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(functionListPage: FunctionListPage) = apply { + service = functionListPage.service + params = functionListPage.params + response = functionListPage.response } - override fun toString() = - "FunctionListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: FunctionService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: FunctionListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: FunctionListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [FunctionListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionListPage = + FunctionListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is FunctionListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: FunctionListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "FunctionListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPageAsync.kt index 2dbc2a78..9e6a8be4 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPageAsync.kt @@ -2,178 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.FunctionServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see FunctionServiceAsync.list */ class FunctionListPageAsync private constructor( - private val functionsService: FunctionServiceAsync, + private val service: FunctionServiceAsync, private val params: FunctionListParams, - private val response: Response, -) { + private val response: FunctionListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [FunctionListPageResponse], but gracefully handles missing data. + * + * @see FunctionListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionListPageAsync && - this.functionsService == other.functionsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - functionsService, - params, - response, - ) - } - - override fun toString() = - "FunctionListPageAsync{functionsService=$functionsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): FunctionListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - FunctionListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): FunctionListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - FunctionListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): FunctionListPageAsync? { - return getNextPageParams()?.let { functionsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - functionsService: FunctionServiceAsync, - params: FunctionListParams, - response: Response - ) = - FunctionListPageAsync( - functionsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): FunctionListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): FunctionListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): FunctionListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [FunctionListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [FunctionListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: FunctionServiceAsync? = null + private var params: FunctionListParams? = null + private var response: FunctionListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(functionListPageAsync: FunctionListPageAsync) = apply { + service = functionListPageAsync.service + params = functionListPageAsync.params + response = functionListPageAsync.response } - override fun toString() = - "FunctionListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: FunctionServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: FunctionListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: FunctionListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [FunctionListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionListPageAsync = + FunctionListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is FunctionListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: FunctionListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "FunctionListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPageResponse.kt new file mode 100644 index 00000000..8fe1d375 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 FunctionListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of function objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [FunctionListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [FunctionListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(functionListPageResponse: FunctionListPageResponse) = apply { + objects = functionListPageResponse.objects.map { it.toMutableList() } + additionalProperties = functionListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of function objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Function] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Function) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [FunctionListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionListPageResponse = + FunctionListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): FunctionListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FunctionListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FunctionListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListParams.kt index e2e38028..49419ecd 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all functions. The functions are sorted by creation date, with the most recently-created + * functions coming first + */ class FunctionListParams -constructor( +private constructor( private val endingBefore: String?, private val functionName: String?, private val ids: Ids?, @@ -31,101 +25,78 @@ constructor( private val slug: String?, private val startingAfter: String?, private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** Name of the function to search for */ fun functionName(): String? = functionName + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Project id */ fun projectId(): String? = projectId + /** Name of the project to search for */ fun projectName(): String? = projectName + /** Retrieve prompt with a specific slug */ fun slug(): String? = slug + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter + /** + * Retrieve prompt at a specific version. + * + * The version id can either be a transaction id (e.g. '1000192656880881099') or a version + * identifier (e.g. '81cd05ee665fdfb3'). + */ fun version(): String? = version - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.functionName?.let { params.put("function_name", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.projectId?.let { params.put("project_id", listOf(it.toString())) } - this.projectName?.let { params.put("project_name", listOf(it.toString())) } - this.slug?.let { params.put("slug", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - this.version?.let { params.put("version", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionListParams && - this.endingBefore == other.endingBefore && - this.functionName == other.functionName && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.projectId == other.projectId && - this.projectName == other.projectName && - this.slug == other.slug && - this.startingAfter == other.startingAfter && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - functionName, - ids, - limit, - orgName, - projectId, - projectName, - slug, - startingAfter, - version, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "FunctionListParams{endingBefore=$endingBefore, functionName=$functionName, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, slug=$slug, startingAfter=$startingAfter, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): FunctionListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FunctionListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [FunctionListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var functionName: String? = null @@ -137,22 +108,22 @@ constructor( private var slug: String? = null private var startingAfter: String? = null private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(functionListParams: FunctionListParams) = apply { - this.endingBefore = functionListParams.endingBefore - this.functionName = functionListParams.functionName - this.ids = functionListParams.ids - this.limit = functionListParams.limit - this.orgName = functionListParams.orgName - this.projectId = functionListParams.projectId - this.projectName = functionListParams.projectName - this.slug = functionListParams.slug - this.startingAfter = functionListParams.startingAfter - this.version = functionListParams.version - additionalQueryParams(functionListParams.additionalQueryParams) - additionalHeaders(functionListParams.additionalHeaders) + endingBefore = functionListParams.endingBefore + functionName = functionListParams.functionName + ids = functionListParams.ids + limit = functionListParams.limit + orgName = functionListParams.orgName + projectId = functionListParams.projectId + projectName = functionListParams.projectName + slug = functionListParams.slug + startingAfter = functionListParams.startingAfter + version = functionListParams.version + additionalHeaders = functionListParams.additionalHeaders.toBuilder() + additionalQueryParams = functionListParams.additionalQueryParams.toBuilder() } /** @@ -162,43 +133,44 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** Name of the function to search for */ - fun functionName(functionName: String) = apply { this.functionName = functionName } + fun functionName(functionName: String?) = apply { this.functionName = functionName } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String?) = apply { this.projectId = projectId } /** Name of the project to search for */ - fun projectName(projectName: String) = apply { this.projectName = projectName } + fun projectName(projectName: String?) = apply { this.projectName = projectName } /** Retrieve prompt with a specific slug */ - fun slug(slug: String) = apply { this.slug = slug } + fun slug(slug: String?) = apply { this.slug = slug } /** * Pagination cursor id. @@ -207,7 +179,7 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } /** * Retrieve prompt at a specific version. @@ -215,48 +187,111 @@ constructor( * The version id can either be a transaction id (e.g. '1000192656880881099') or a version * identifier (e.g. '81cd05ee665fdfb3'). */ - fun version(version: String) = apply { this.version = version } + fun version(version: String?) = apply { this.version = version } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [FunctionListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): FunctionListParams = FunctionListParams( endingBefore, @@ -269,22 +304,50 @@ constructor( slug, startingAfter, version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + functionName?.let { put("function_name", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + projectId?.let { put("project_id", it) } + projectName?.let { put("project_name", it) } + slug?.let { put("slug", it) } + startingAfter?.let { put("starting_after", it) } + version?.let { put("version", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -297,93 +360,82 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is FunctionListParams && + endingBefore == other.endingBefore && + functionName == other.functionName && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + projectId == other.projectId && + projectName == other.projectName && + slug == other.slug && + startingAfter == other.startingAfter && + version == other.version && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + functionName, + ids, + limit, + orgName, + projectId, + projectName, + slug, + startingAfter, + version, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "FunctionListParams{endingBefore=$endingBefore, functionName=$functionName, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, slug=$slug, startingAfter=$startingAfter, version=$version, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionReplaceParams.kt index 4f5e3472..b4030981 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionReplaceParams.kt @@ -9,9 +9,14 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.braintrustdata.api.models.CodeBundle.* import com.fasterxml.jackson.annotation.JsonAnyGetter @@ -25,291 +30,542 @@ 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 +/** + * Create or replace function. If there is an existing function in the project with the same slug as + * the one specified in the request, will replace the existing function with the provided fields + */ class FunctionReplaceParams -constructor( - private val functionData: FunctionData, - private val name: String, - private val projectId: String, - private val slug: String, - private val description: String?, - private val functionSchema: FunctionSchema?, - private val functionType: FunctionType?, - private val origin: Origin?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * @throws BraintrustInvalidDataException 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 functionData(): FunctionData = body.functionData() + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = body.slug() + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * JSON schema for the function's parameters and return type + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionSchema(): FunctionSchema? = body.functionSchema() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionType(): FunctionType? = body.functionType() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun origin(): Origin? = body.origin() + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = body.promptData() + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = body.tags() + + /** + * Returns the raw JSON value of [functionData]. + * + * Unlike [functionData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionData(): JsonField = body._functionData() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _slug(): JsonField = body._slug() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [functionSchema]. + * + * Unlike [functionSchema], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionSchema(): JsonField = body._functionSchema() + + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionType(): JsonField = body._functionType() + + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _origin(): JsonField = body._origin() + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _promptData(): JsonField = body._promptData() + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tags(): JsonField> = body._tags() + + 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 functionData(): FunctionData = functionData - - fun name(): String = name - - fun projectId(): String = projectId + fun toBuilder() = Builder().from(this) - fun slug(): String = slug + companion object { - fun description(): String? = description + /** + * Returns a mutable builder for constructing an instance of [FunctionReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() + } - fun functionSchema(): FunctionSchema? = functionSchema + /** A builder for [FunctionReplaceParams]. */ + class Builder internal constructor() { - fun functionType(): FunctionType? = functionType + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun origin(): Origin? = origin + internal fun from(functionReplaceParams: FunctionReplaceParams) = apply { + body = functionReplaceParams.body.toBuilder() + additionalHeaders = functionReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = functionReplaceParams.additionalQueryParams.toBuilder() + } - fun promptData(): PromptData? = promptData + /** + * 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: + * - [functionData] + * - [name] + * - [projectId] + * - [slug] + * - [description] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } - fun tags(): List? = tags + fun functionData(functionData: FunctionData) = apply { body.functionData(functionData) } - internal fun getBody(): FunctionReplaceBody { - return FunctionReplaceBody( - functionData, - name, - projectId, - slug, - description, - functionSchema, - functionType, - origin, - promptData, - tags, - additionalBodyProperties, - ) - } + /** + * Sets [Builder.functionData] to an arbitrary JSON value. + * + * You should usually call [Builder.functionData] with a well-typed [FunctionData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionData(functionData: JsonField) = apply { + body.functionData(functionData) + } - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = FunctionReplaceBody.Builder::class) - @NoAutoDetect - class FunctionReplaceBody - internal constructor( - private val functionData: FunctionData?, - private val name: String?, - private val projectId: String?, - private val slug: String?, - private val description: String?, - private val functionSchema: FunctionSchema?, - private val functionType: FunctionType?, - private val origin: Origin?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalProperties: Map, - ) { + /** Alias for calling [functionData] with `FunctionData.ofPrompt(prompt)`. */ + fun functionData(prompt: FunctionData.Prompt) = apply { body.functionData(prompt) } - private var hashCode: Int = 0 + /** Alias for calling [functionData] with `FunctionData.ofCode(code)`. */ + fun functionData(code: FunctionData.Code) = apply { body.functionData(code) } - @JsonProperty("function_data") fun functionData(): FunctionData? = functionData + /** Alias for calling [functionData] with `FunctionData.ofGlobal(global)`. */ + fun functionData(global: FunctionData.Global) = apply { body.functionData(global) } /** Name of the prompt */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(): String? = slug + fun slug(slug: String) = apply { body.slug(slug) } + + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun slug(slug: JsonField) = apply { body.slug(slug) } /** Textual description of the prompt */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** JSON schema for the function's parameters and return type */ - @JsonProperty("function_schema") fun functionSchema(): FunctionSchema? = functionSchema + fun functionSchema(functionSchema: FunctionSchema?) = apply { + body.functionSchema(functionSchema) + } + + /** + * Sets [Builder.functionSchema] to an arbitrary JSON value. + * + * You should usually call [Builder.functionSchema] with a well-typed [FunctionSchema] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionSchema(functionSchema: JsonField) = apply { + body.functionSchema(functionSchema) + } - @JsonProperty("function_type") fun functionType(): FunctionType? = functionType + fun functionType(functionType: FunctionType?) = apply { body.functionType(functionType) } - @JsonProperty("origin") fun origin(): Origin? = origin + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + body.functionType(functionType) + } + + fun origin(origin: Origin?) = apply { body.origin(origin) } + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [Origin] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun origin(origin: JsonField) = apply { body.origin(origin) } /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") fun promptData(): PromptData? = promptData + fun promptData(promptData: PromptData?) = apply { body.promptData(promptData) } + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { body.promptData(promptData) } /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(): List? = tags + fun tags(tags: List?) = apply { body.tags(tags) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { body.tags(tags) } - fun toBuilder() = Builder().from(this) + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { body.addTag(tag) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - return other is FunctionReplaceBody && - this.functionData == other.functionData && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionSchema == other.functionSchema && - this.functionType == other.functionType && - this.origin == other.origin && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalProperties == other.additionalProperties + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - functionData, - name, - projectId, - slug, - description, - functionSchema, - functionType, - origin, - promptData, - tags, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "FunctionReplaceBody{functionData=$functionData, name=$name, projectId=$projectId, slug=$slug, description=$description, functionSchema=$functionSchema, functionType=$functionType, origin=$origin, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { - - private var functionData: FunctionData? = null - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionSchema: FunctionSchema? = null - private var functionType: FunctionType? = null - private var origin: Origin? = null - private var promptData: PromptData? = null - private var tags: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - internal fun from(functionReplaceBody: FunctionReplaceBody) = apply { - this.functionData = functionReplaceBody.functionData - this.name = functionReplaceBody.name - this.projectId = functionReplaceBody.projectId - this.slug = functionReplaceBody.slug - this.description = functionReplaceBody.description - this.functionSchema = functionReplaceBody.functionSchema - this.functionType = functionReplaceBody.functionType - this.origin = functionReplaceBody.origin - this.promptData = functionReplaceBody.promptData - this.tags = functionReplaceBody.tags - additionalProperties(functionReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @JsonProperty("function_data") - fun functionData(functionData: FunctionData) = apply { - this.functionData = functionData - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the prompt */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(slug: String) = apply { this.slug = slug } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Textual description of the prompt */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** JSON schema for the function's parameters and return type */ - @JsonProperty("function_schema") - fun functionSchema(functionSchema: FunctionSchema) = apply { - this.functionSchema = functionSchema - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - @JsonProperty("function_type") - fun functionType(functionType: FunctionType) = apply { - this.functionType = functionType - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonProperty("origin") fun origin(origin: Origin) = apply { this.origin = origin } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(tags: List) = apply { this.tags = tags } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun build(): FunctionReplaceBody = - FunctionReplaceBody( - checkNotNull(functionData) { "`functionData` is required but was not set" }, - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, - description, - functionSchema, - functionType, - origin, - promptData, - tags?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is FunctionReplaceParams && - this.functionData == other.functionData && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionSchema == other.functionSchema && - this.functionType == other.functionType && - this.origin == other.origin && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [FunctionReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FunctionReplaceParams = + FunctionReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( + 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 functionData: JsonField, + private val name: JsonField, + private val projectId: JsonField, + private val slug: JsonField, + private val description: JsonField, + private val functionSchema: JsonField, + private val functionType: JsonField, + private val origin: JsonField, + private val promptData: JsonField, + private val tags: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("function_data") + @ExcludeMissing + functionData: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("function_schema") + @ExcludeMissing + functionSchema: JsonField = JsonMissing.of(), + @JsonProperty("function_type") + @ExcludeMissing + functionType: JsonField = JsonMissing.of(), + @JsonProperty("origin") @ExcludeMissing origin: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( functionData, name, projectId, @@ -320,172 +576,510 @@ constructor( origin, promptData, tags, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - override fun toString() = - "FunctionReplaceParams{functionData=$functionData, name=$name, projectId=$projectId, slug=$slug, description=$description, functionSchema=$functionSchema, functionType=$functionType, origin=$origin, promptData=$promptData, tags=$tags, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + /** + * @throws BraintrustInvalidDataException 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 functionData(): FunctionData = functionData.getRequired("function_data") - fun toBuilder() = Builder().from(this) + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - companion object { + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - fun builder() = Builder() - } + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") - @NoAutoDetect - class Builder { - - private var functionData: FunctionData? = null - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionSchema: FunctionSchema? = null - private var functionType: FunctionType? = null - private var origin: Origin? = null - private var promptData: PromptData? = null - private var tags: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - internal fun from(functionReplaceParams: FunctionReplaceParams) = apply { - this.functionData = functionReplaceParams.functionData - this.name = functionReplaceParams.name - this.projectId = functionReplaceParams.projectId - this.slug = functionReplaceParams.slug - this.description = functionReplaceParams.description - this.functionSchema = functionReplaceParams.functionSchema - this.functionType = functionReplaceParams.functionType - this.origin = functionReplaceParams.origin - this.promptData = functionReplaceParams.promptData - this.tags(functionReplaceParams.tags ?: listOf()) - additionalQueryParams(functionReplaceParams.additionalQueryParams) - additionalHeaders(functionReplaceParams.additionalHeaders) - additionalBodyProperties(functionReplaceParams.additionalBodyProperties) - } + /** + * JSON schema for the function's parameters and return type + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun functionSchema(): FunctionSchema? = functionSchema.getNullable("function_schema") - fun functionData(functionData: FunctionData) = apply { this.functionData = functionData } + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun functionType(): FunctionType? = functionType.getNullable("function_type") - fun functionData(prompt: FunctionData.Prompt) = apply { - this.functionData = FunctionData.ofPrompt(prompt) - } + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun origin(): Origin? = origin.getNullable("origin") - fun functionData(code: FunctionData.Code) = apply { - this.functionData = FunctionData.ofCode(code) - } + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") - fun functionData(global: FunctionData.Global) = apply { - this.functionData = FunctionData.ofGlobal(global) - } + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") - /** Name of the prompt */ - fun name(name: String) = apply { this.name = name } + /** + * Returns the raw JSON value of [functionData]. + * + * Unlike [functionData], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_data") + @ExcludeMissing + fun _functionData(): JsonField = functionData - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Unique identifier for the prompt */ - fun slug(slug: String) = apply { this.slug = slug } + /** + * 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 - /** Textual description of the prompt */ - fun description(description: String) = apply { this.description = description } + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug - /** JSON schema for the function's parameters and return type */ - fun functionSchema(functionSchema: FunctionSchema) = apply { - this.functionSchema = functionSchema - } + /** + * 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 - fun functionType(functionType: FunctionType) = apply { this.functionType = functionType } + /** + * Returns the raw JSON value of [functionSchema]. + * + * Unlike [functionSchema], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_schema") + @ExcludeMissing + fun _functionSchema(): JsonField = functionSchema - fun origin(origin: Origin) = apply { this.origin = origin } + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_type") + @ExcludeMissing + fun _functionType(): JsonField = functionType - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin - /** A list of tags for the prompt */ - fun tags(tags: List) = apply { - this.tags.clear() - this.tags.addAll(tags) - } + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") + @ExcludeMissing + fun _promptData(): JsonField = promptData - /** A list of tags for the prompt */ - fun addTag(tag: String) = apply { this.tags.add(tag) } + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + companion object { - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var functionData: JsonField? = null + private var name: JsonField? = null + private var projectId: JsonField? = null + private var slug: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var functionSchema: JsonField = JsonMissing.of() + private var functionType: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + internal fun from(body: Body) = apply { + functionData = body.functionData + name = body.name + projectId = body.projectId + slug = body.slug + description = body.description + functionSchema = body.functionSchema + functionType = body.functionType + origin = body.origin + promptData = body.promptData + tags = body.tags.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun functionData(functionData: FunctionData) = functionData(JsonField.of(functionData)) - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** + * Sets [Builder.functionData] to an arbitrary JSON value. + * + * You should usually call [Builder.functionData] with a well-typed [FunctionData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionData(functionData: JsonField) = apply { + this.functionData = functionData + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** Alias for calling [functionData] with `FunctionData.ofPrompt(prompt)`. */ + fun functionData(prompt: FunctionData.Prompt) = + functionData(FunctionData.ofPrompt(prompt)) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Alias for calling [functionData] with `FunctionData.ofCode(code)`. */ + fun functionData(code: FunctionData.Code) = functionData(FunctionData.ofCode(code)) + + /** Alias for calling [functionData] with `FunctionData.ofGlobal(global)`. */ + fun functionData(global: FunctionData.Global) = + functionData(FunctionData.ofGlobal(global)) + + /** Name of the prompt */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Unique identifier for the project that the prompt belongs under */ + 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 } + + /** Unique identifier for the prompt */ + fun slug(slug: String) = slug(JsonField.of(slug)) + + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun slug(slug: JsonField) = apply { this.slug = slug } + + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** JSON schema for the function's parameters and return type */ + fun functionSchema(functionSchema: FunctionSchema?) = + functionSchema(JsonField.ofNullable(functionSchema)) + + /** + * Sets [Builder.functionSchema] to an arbitrary JSON value. + * + * You should usually call [Builder.functionSchema] with a well-typed [FunctionSchema] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun functionSchema(functionSchema: JsonField) = apply { + this.functionSchema = functionSchema + } + + fun functionType(functionType: FunctionType?) = + functionType(JsonField.ofNullable(functionType)) + + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + this.functionType = functionType + } + + fun origin(origin: Origin?) = origin(JsonField.ofNullable(origin)) + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [Origin] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun origin(origin: JsonField) = apply { this.origin = origin } + + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { + this.promptData = promptData + } + + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = + (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + + 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: + * ```kotlin + * .functionData() + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("functionData", functionData), + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("slug", slug), + description, + functionSchema, + functionType, + origin, + promptData, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + functionData().validate() + name() + projectId() + slug() + description() + functionSchema()?.validate() + functionType()?.validate() + origin()?.validate() + promptData()?.validate() + tags() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): FunctionReplaceParams = - FunctionReplaceParams( - checkNotNull(functionData) { "`functionData` is required but was not set" }, - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (functionData.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (functionSchema.asKnown()?.validity() ?: 0) + + (functionType.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (promptData.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + functionData == other.functionData && + name == other.name && + projectId == other.projectId && + slug == other.slug && + description == other.description && + functionSchema == other.functionSchema && + functionType == other.functionType && + origin == other.origin && + promptData == other.promptData && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + functionData, + name, + projectId, + slug, description, functionSchema, functionType, origin, promptData, - if (tags.size == 0) null else tags.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + tags, + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{functionData=$functionData, name=$name, projectId=$projectId, slug=$slug, description=$description, functionSchema=$functionSchema, functionType=$functionType, origin=$origin, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" } @JsonDeserialize(using = FunctionData.Deserializer::class) @@ -498,8 +1092,6 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun prompt(): Prompt? = prompt fun code(): Code? = code @@ -520,55 +1112,87 @@ constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { prompt != null -> visitor.visitPrompt(prompt) code != null -> visitor.visitCode(code) global != null -> visitor.visitGlobal(global) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): FunctionData = apply { - if (!validated) { - if (prompt == null && code == null && global == null) { - throw BraintrustInvalidDataException("Unknown FunctionData: $_json") - } - prompt?.validate() - code?.validate() - global?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) { + prompt.validate() + } + + override fun visitCode(code: Code) { + code.validate() + } + + override fun visitGlobal(global: Global) { + global.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) = prompt.validity() + + override fun visitCode(code: Code) = code.validity() + + override fun visitGlobal(global: Global) = global.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is FunctionData && - this.prompt == other.prompt && - this.code == other.code && - this.global == other.global + prompt == other.prompt && + code == other.code && + global == other.global } - override fun hashCode(): Int { - return Objects.hash( - prompt, - code, - global, - ) - } + override fun hashCode(): Int = Objects.hash(prompt, code, global) - override fun toString(): String { - return when { + override fun toString(): String = + when { prompt != null -> "FunctionData{prompt=$prompt}" code != null -> "FunctionData{code=$code}" global != null -> "FunctionData{global=$global}" _json != null -> "FunctionData{_unknown=$_json}" else -> throw IllegalStateException("Invalid FunctionData") } - } companion object { @@ -579,6 +1203,10 @@ constructor( fun ofGlobal(global: Global) = FunctionData(global = global) } + /** + * An interface that defines how to map each variant of [FunctionData] to a value of type + * [T]. + */ interface Visitor { fun visitPrompt(prompt: Prompt): T @@ -587,38 +1215,60 @@ constructor( fun visitGlobal(global: Global): T + /** + * Maps an unknown variant of [FunctionData] to a value of type [T]. + * + * An instance of [FunctionData] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown FunctionData: $json") } } - class Deserializer : BaseDeserializer(FunctionData::class) { + internal class Deserializer : BaseDeserializer(FunctionData::class) { override fun ObjectCodec.deserialize(node: JsonNode): FunctionData { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(prompt = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(code = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(global = it, _json = json) - } - return FunctionData(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(prompt = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(code = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(global = 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 -> FunctionData(_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() + } } } - class Serializer : BaseSerializer(FunctionData::class) { + internal class Serializer : BaseSerializer(FunctionData::class) { override fun serialize( value: FunctionData, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.prompt != null -> generator.writeObject(value.prompt) @@ -630,84 +1280,86 @@ constructor( } } - @JsonDeserialize(builder = Prompt.Builder::class) - @NoAutoDetect class Prompt + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of() + ) : this(type, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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 = additionalProperties - - fun validate(): Prompt = apply { - if (!validated) { - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Prompt && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(type, additionalProperties) - } - return hashCode - } - - override fun toString() = - "Prompt{type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Prompt]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Prompt]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(prompt: Prompt) = apply { - this.type = prompt.type - additionalProperties(prompt.additionalProperties) + type = prompt.type + additionalProperties = prompt.additionalProperties.toMutableMap() } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -715,159 +1367,314 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Prompt = Prompt(type, additionalProperties.toUnmodifiable()) - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns an immutable instance of [Prompt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Prompt = + Prompt(checkRequired("type", type), additionalProperties.toMutableMap()) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Type && this.value == other.value + fun validate(): Prompt = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() + type().validate() + validated = true + } - override fun toString() = value.toString() + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (type.asKnown()?.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 { - val PROMPT = Type(JsonField.of("prompt")) + val PROMPT = of("prompt") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - PROMPT, + PROMPT } + /** + * 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 { PROMPT, + /** + * 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) { PROMPT -> Value.PROMPT 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { PROMPT -> Known.PROMPT else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Code.Builder::class) - @NoAutoDetect - class Code - private constructor( - private val type: JsonField, - private val data: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun data(): Data = data.getRequired("data") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("data") @ExcludeMissing fun _data() = data + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Code = apply { - if (!validated) { - type() - data() - validated = true + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Prompt && + type == other.type && + additionalProperties == other.additionalProperties } - fun toBuilder() = Builder().from(this) + private val hashCode: Int by lazy { Objects.hash(type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Prompt{type=$type, additionalProperties=$additionalProperties}" + } + + class Code + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val data: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(data, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 BraintrustInvalidDataException 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 [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * 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 - return other is Code && - this.type == other.type && - this.data == other.data && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - data, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Code{type=$type, data=$data, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Code]. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Code]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var data: JsonField = JsonMissing.of() + private var data: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(code: Code) = apply { - this.type = code.type - this.data = code.data - additionalProperties(code.additionalProperties) + data = code.data + type = code.type + additionalProperties = code.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun data(data: Data) = data(JsonField.of(data)) - @JsonProperty("data") - @ExcludeMissing + /** + * 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.ofBundle(bundle)`. */ + fun data(bundle: Data.Bundle) = data(Data.ofBundle(bundle)) + + /** Alias for calling [data] with `Data.ofInline(inline)`. */ + fun data(inline: Data.Inline) = data(Data.ofInline(inline)) + + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -875,14 +1682,64 @@ constructor( 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 [Code]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Code = Code( - type, - data, - additionalProperties.toUnmodifiable(), + checkRequired("data", data), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Code = apply { + if (validated) { + return@apply + } + + data().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (data.asKnown()?.validity() ?: 0) + (type.asKnown()?.validity() ?: 0) + @JsonDeserialize(using = Data.Deserializer::class) @JsonSerialize(using = Data.Serializer::class) class Data @@ -892,8 +1749,6 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun bundle(): Bundle? = bundle fun inline(): Inline? = inline @@ -908,46 +1763,76 @@ constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { bundle != null -> visitor.visitBundle(bundle) inline != null -> visitor.visitInline(inline) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Data = apply { - if (!validated) { - if (bundle == null && inline == null) { - throw BraintrustInvalidDataException("Unknown Data: $_json") - } - inline?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) { + bundle.validate() + } + + override fun visitInline(inline: Inline) { + inline.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) = bundle.validity() + + override fun visitInline(inline: Inline) = inline.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Data && - this.bundle == other.bundle && - this.inline == other.inline + return other is Data && bundle == other.bundle && inline == other.inline } - override fun hashCode(): Int { - return Objects.hash(bundle, inline) - } + override fun hashCode(): Int = Objects.hash(bundle, inline) - override fun toString(): String { - return when { + override fun toString(): String = + when { bundle != null -> "Data{bundle=$bundle}" inline != null -> "Data{inline=$inline}" _json != null -> "Data{_unknown=$_json}" else -> throw IllegalStateException("Invalid Data") } - } companion object { @@ -956,39 +1841,68 @@ constructor( fun ofInline(inline: Inline) = Data(inline = inline) } + /** + * An interface that defines how to map each variant of [Data] to a value of type + * [T]. + */ interface Visitor { fun visitBundle(bundle: Bundle): T fun visitInline(inline: Inline): 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Data: $json") } } - class Deserializer : BaseDeserializer(Data::class) { + internal class Deserializer : BaseDeserializer(Data::class) { override fun ObjectCodec.deserialize(node: JsonNode): Data { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Data(bundle = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Data(inline = it, _json = json) - } - return Data(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Data(bundle = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Data(inline = 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() + } } } - class Serializer : BaseSerializer(Data::class) { + internal class Serializer : BaseSerializer(Data::class) { override fun serialize( value: Data, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.bundle != null -> generator.writeObject(value.bundle) @@ -999,474 +1913,840 @@ constructor( } } - @JsonDeserialize(builder = Bundle.Builder::class) - @NoAutoDetect class Bundle + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val runtimeContext: JsonField, - private val location: JsonField, private val bundleId: JsonField, + private val location: JsonField, + private val runtimeContext: JsonField, private val preview: JsonField, private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun runtimeContext(): RuntimeContext = - runtimeContext.getRequired("runtime_context") - - fun location(): Location = location.getRequired("location") - - fun bundleId(): String = bundleId.getRequired("bundle_id") - - /** A preview of the code */ - fun preview(): String? = preview.getNullable("preview") - - fun type(): Type = type.getRequired("type") + @JsonCreator + private constructor( + @JsonProperty("bundle_id") + @ExcludeMissing + bundleId: JsonField = JsonMissing.of(), + @JsonProperty("location") + @ExcludeMissing + location: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("preview") + @ExcludeMissing + preview: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(bundleId, location, runtimeContext, preview, type, mutableMapOf()) fun toCodeBundle(): CodeBundle = CodeBundle.builder() - .runtimeContext(runtimeContext) - .location(location) .bundleId(bundleId) + .location(location) + .runtimeContext(runtimeContext) .preview(preview) .build() - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + /** + * @throws BraintrustInvalidDataException 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 bundleId(): String = bundleId.getRequired("bundle_id") - @JsonProperty("location") @ExcludeMissing fun _location() = location + /** + * @throws BraintrustInvalidDataException 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 location(): CodeBundle.Location = location.getRequired("location") + + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): CodeBundle.RuntimeContext = + runtimeContext.getRequired("runtime_context") - @JsonProperty("bundle_id") @ExcludeMissing fun _bundleId() = bundleId + /** + * A preview of the code + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun preview(): String? = preview.getNullable("preview") - /** A preview of the code */ - @JsonProperty("preview") @ExcludeMissing fun _preview() = preview + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * Returns the raw JSON value of [bundleId]. + * + * Unlike [bundleId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("bundle_id") + @ExcludeMissing + fun _bundleId(): JsonField = bundleId + + /** + * 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 [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * Returns the raw JSON value of [preview]. + * + * Unlike [preview], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("preview") + @ExcludeMissing + fun _preview(): JsonField = preview + + /** + * 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 = additionalProperties - - fun validate(): Bundle = apply { - if (!validated) { - runtimeContext().validate() - location() - bundleId() - preview() - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Bundle && - this.runtimeContext == other.runtimeContext && - this.location == other.location && - this.bundleId == other.bundleId && - this.preview == other.preview && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtimeContext, - location, - bundleId, - preview, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Bundle{runtimeContext=$runtimeContext, location=$location, bundleId=$bundleId, preview=$preview, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Bundle]. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Bundle]. */ + class Builder internal constructor() { - private var runtimeContext: JsonField = JsonMissing.of() - private var location: JsonField = JsonMissing.of() - private var bundleId: JsonField = JsonMissing.of() + private var bundleId: JsonField? = null + private var location: JsonField? = null + private var runtimeContext: JsonField? = null private var preview: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(bundle: Bundle) = apply { - this.runtimeContext = bundle.runtimeContext - this.location = bundle.location - this.bundleId = bundle.bundleId - this.preview = bundle.preview - this.type = bundle.type - additionalProperties(bundle.additionalProperties) + bundleId = bundle.bundleId + location = bundle.location + runtimeContext = bundle.runtimeContext + preview = bundle.preview + type = bundle.type + additionalProperties = bundle.additionalProperties.toMutableMap() } - fun runtimeContext(runtimeContext: RuntimeContext) = - runtimeContext(JsonField.of(runtimeContext)) + fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - @JsonProperty("runtime_context") - @ExcludeMissing - fun runtimeContext(runtimeContext: JsonField) = apply { - this.runtimeContext = runtimeContext + /** + * Sets [Builder.bundleId] to an arbitrary JSON value. + * + * You should usually call [Builder.bundleId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun bundleId(bundleId: JsonField) = apply { + this.bundleId = bundleId } - fun location(location: Location) = location(JsonField.of(location)) - - @JsonProperty("location") - @ExcludeMissing - fun location(location: JsonField) = apply { + fun location(location: CodeBundle.Location) = + location(JsonField.of(location)) + + /** + * Sets [Builder.location] to an arbitrary JSON value. + * + * You should usually call [Builder.location] with a well-typed + * [CodeBundle.Location] 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 } - fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - - @JsonProperty("bundle_id") - @ExcludeMissing - fun bundleId(bundleId: JsonField) = apply { - this.bundleId = bundleId - } + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofExperiment(experiment)`. + */ + fun location(experiment: CodeBundle.Location.Experiment) = + location(CodeBundle.Location.ofExperiment(experiment)) + + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofFunction(function)`. + */ + fun location(function: CodeBundle.Location.Function) = + location(CodeBundle.Location.ofFunction(function)) + + fun runtimeContext(runtimeContext: CodeBundle.RuntimeContext) = + runtimeContext(JsonField.of(runtimeContext)) - /** A preview of the code */ - fun preview(preview: String) = preview(JsonField.of(preview)) + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [CodeBundle.RuntimeContext] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun runtimeContext(runtimeContext: JsonField) = + apply { + this.runtimeContext = runtimeContext + } /** A preview of the code */ - @JsonProperty("preview") - @ExcludeMissing + fun preview(preview: String?) = preview(JsonField.ofNullable(preview)) + + /** + * Sets [Builder.preview] to an arbitrary JSON value. + * + * You should usually call [Builder.preview] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun preview(preview: JsonField) = apply { this.preview = preview } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Bundle]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Bundle = Bundle( - runtimeContext, - location, - bundleId, + checkRequired("bundleId", bundleId), + checkRequired("location", location), + checkRequired("runtimeContext", runtimeContext), preview, - type, - additionalProperties.toUnmodifiable(), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Bundle = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + bundleId() + location().validate() + runtimeContext().validate() + preview() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (bundleId.asKnown() == null) 0 else 1) + + (location.asKnown()?.validity() ?: 0) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (if (preview.asKnown() == null) 0 else 1) + + (type.asKnown()?.validity() ?: 0) - override fun toString() = value.toString() + 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 { - val BUNDLE = Type(JsonField.of("bundle")) + val BUNDLE = of("bundle") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - BUNDLE, + BUNDLE } + /** + * 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 { BUNDLE, + /** + * 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) { BUNDLE -> Value.BUNDLE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { BUNDLE -> Known.BUNDLE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - - @JsonDeserialize(builder = Inline.Builder::class) - @NoAutoDetect - class Inline - private constructor( - private val type: JsonField, - private val runtimeContext: JsonField, - private val code: JsonField, - private val additionalProperties: Map, - ) { + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - private var validated: Boolean = false + private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Type = apply { + if (validated) { + return@apply + } - fun type(): Type = type.getRequired("type") + known() + validated = true + } - fun runtimeContext(): RuntimeContext = - runtimeContext.getRequired("runtime_context") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun code(): String = code.getRequired("code") + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + return other is Type && value == other.value + } - @JsonProperty("code") @ExcludeMissing fun _code() = code + override fun hashCode() = value.hashCode() - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun toString() = value.toString() + } - fun validate(): Inline = apply { - if (!validated) { - type() - runtimeContext().validate() - code() - validated = true + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Bundle && + bundleId == other.bundleId && + location == other.location && + runtimeContext == other.runtimeContext && + preview == other.preview && + type == other.type && + additionalProperties == other.additionalProperties } - fun toBuilder() = Builder().from(this) + private val hashCode: Int by lazy { + Objects.hash( + bundleId, + location, + runtimeContext, + preview, + type, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Bundle{bundleId=$bundleId, location=$location, runtimeContext=$runtimeContext, preview=$preview, type=$type, additionalProperties=$additionalProperties}" + } + + class Inline + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val code: JsonField, + private val runtimeContext: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("code") + @ExcludeMissing + code: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(code, runtimeContext, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 code(): String = code.getRequired("code") + + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): RuntimeContext = + runtimeContext.getRequired("runtime_context") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * @throws BraintrustInvalidDataException 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") - return other is Inline && - this.type == other.type && - this.runtimeContext == other.runtimeContext && - this.code == other.code && - this.additionalProperties == other.additionalProperties + /** + * Returns the raw JSON value of [code]. + * + * Unlike [code], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("code") @ExcludeMissing fun _code(): JsonField = code + + /** + * Returns the raw JSON value of [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * 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) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - runtimeContext, - code, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Inline{type=$type, runtimeContext=$runtimeContext, code=$code, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Inline]. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Inline]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var runtimeContext: JsonField = JsonMissing.of() - private var code: JsonField = JsonMissing.of() + private var code: JsonField? = null + private var runtimeContext: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inline: Inline) = apply { - this.type = inline.type - this.runtimeContext = inline.runtimeContext - this.code = inline.code - additionalProperties(inline.additionalProperties) + code = inline.code + runtimeContext = inline.runtimeContext + type = inline.type + additionalProperties = inline.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) + fun code(code: String) = code(JsonField.of(code)) - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } + /** + * Sets [Builder.code] to an arbitrary JSON value. + * + * You should usually call [Builder.code] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun code(code: JsonField) = apply { this.code = code } fun runtimeContext(runtimeContext: RuntimeContext) = runtimeContext(JsonField.of(runtimeContext)) - @JsonProperty("runtime_context") - @ExcludeMissing + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [RuntimeContext] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ fun runtimeContext(runtimeContext: JsonField) = apply { this.runtimeContext = runtimeContext } - fun code(code: String) = code(JsonField.of(code)) + fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("code") - @ExcludeMissing - fun code(code: JsonField) = apply { this.code = code } + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Inline]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Inline = Inline( - type, - runtimeContext, - code, - additionalProperties.toUnmodifiable(), + checkRequired("code", code), + checkRequired("runtimeContext", runtimeContext), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = RuntimeContext.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): Inline = apply { + if (validated) { + return@apply + } + + code() + runtimeContext().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (code.asKnown() == null) 0 else 1) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (type.asKnown()?.validity() ?: 0) + class RuntimeContext + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val runtime: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("runtime") + @ExcludeMissing + runtime: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(runtime, version, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 runtime(): Runtime = runtime.getRequired("runtime") + /** + * @throws BraintrustInvalidDataException 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 version(): String = version.getRequired("version") - @JsonProperty("runtime") @ExcludeMissing fun _runtime() = runtime + /** + * Returns the raw JSON value of [runtime]. + * + * Unlike [runtime], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime") + @ExcludeMissing + fun _runtime(): JsonField = runtime + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("version") + @ExcludeMissing + fun _version(): JsonField = version - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): RuntimeContext = apply { - if (!validated) { - runtime() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RuntimeContext && - this.runtime == other.runtime && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtime, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [RuntimeContext]. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RuntimeContext]. */ + class Builder internal constructor() { - private var runtime: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() + private var runtime: JsonField? = null + private var version: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(runtimeContext: RuntimeContext) = apply { - this.runtime = runtimeContext.runtime - this.version = runtimeContext.version - additionalProperties(runtimeContext.additionalProperties) + runtime = runtimeContext.runtime + version = runtimeContext.version + additionalProperties = + runtimeContext.additionalProperties.toMutableMap() } fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) - @JsonProperty("runtime") - @ExcludeMissing + /** + * Sets [Builder.runtime] to an arbitrary JSON value. + * + * You should usually call [Builder.runtime] with a well-typed [Runtime] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun runtime(runtime: JsonField) = apply { this.runtime = runtime } fun version(version: String) = version(JsonField.of(version)) - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } @@ -1474,67 +2754,136 @@ constructor( fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RuntimeContext]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RuntimeContext = RuntimeContext( - runtime, - version, - additionalProperties.toUnmodifiable(), + checkRequired("runtime", runtime), + checkRequired("version", version), + additionalProperties.toMutableMap(), ) } - class Runtime - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): RuntimeContext = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + runtime().validate() + version() + validated = true + } - return other is Runtime && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (runtime.asKnown()?.validity() ?: 0) + + (if (version.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Runtime + @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 { - val NODE = Runtime(JsonField.of("node")) + val NODE = of("node") - val PYTHON = Runtime(JsonField.of("python")) + val PYTHON = of("python") fun of(value: String) = Runtime(JsonField.of(value)) } + /** An enum containing [Runtime]'s known values. */ enum class Known { NODE, PYTHON, } + /** + * An enum containing [Runtime]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Runtime] 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 { NODE, PYTHON, + /** + * An enum member indicating that [Runtime] 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) { NODE -> Value.NODE @@ -1542,6 +2891,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value + * is a not a known member. + */ fun known(): Known = when (this) { NODE -> Known.NODE @@ -1552,214 +2910,482 @@ constructor( ) } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Runtime = apply { + if (validated) { + return@apply + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + 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 Runtime && 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 Type && this.value == other.value + return other is RuntimeContext && + runtime == other.runtime && + version == other.version && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(runtime, version, additionalProperties) } - override fun hashCode() = value.hashCode() + override fun hashCode(): Int = hashCode - override fun toString() = value.toString() + override fun toString() = + "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + } + + 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 { - val INLINE = Type(JsonField.of("inline")) + val INLINE = of("inline") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - INLINE, + INLINE } + /** + * 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 { INLINE, + /** + * 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) { INLINE -> Value.INLINE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { INLINE -> Known.INLINE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + return other is Inline && + code == other.code && + runtimeContext == other.runtimeContext && + type == other.type && + additionalProperties == other.additionalProperties + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + private val hashCode: Int by lazy { + Objects.hash(code, runtimeContext, type, additionalProperties) } - return other is Type && this.value == other.value - } + override fun hashCode(): Int = hashCode - override fun hashCode() = value.hashCode() + override fun toString() = + "Inline{code=$code, runtimeContext=$runtimeContext, type=$type, additionalProperties=$additionalProperties}" + } + } - override fun toString() = value.toString() + 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 { - val CODE = Type(JsonField.of("code")) + val CODE = of("code") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - CODE, + CODE } + /** + * 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 { CODE, + /** + * 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) { CODE -> Value.CODE 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { CODE -> Known.CODE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Global.Builder::class) - @NoAutoDetect - class Global - private constructor( - private val type: JsonField, - private val name: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun name(): String = name.getRequired("name") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("name") @ExcludeMissing fun _name() = name + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Global = apply { - if (!validated) { - type() - name() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Global && - this.type == other.type && - this.name == other.name && - this.additionalProperties == other.additionalProperties + return other is Code && + data == other.data && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - name, - additionalProperties, - ) - } - return hashCode + private val hashCode: Int by lazy { Objects.hash(data, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Code{data=$data, type=$type, additionalProperties=$additionalProperties}" + } + + class Global + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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) } - override fun toString() = - "Global{type=$type, name=$name, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Global]. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Global]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var name: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(global: Global) = apply { - this.type = global.type - this.name = global.name - additionalProperties(global.additionalProperties) + name = global.name + type = global.type + additionalProperties = global.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1767,194 +3393,363 @@ constructor( 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 [Global]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Global = Global( - type, - name, - additionalProperties.toUnmodifiable(), + checkRequired("name", name), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Global = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val GLOBAL = Type(JsonField.of("global")) + val GLOBAL = of("global") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - GLOBAL, + GLOBAL } + /** + * 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 { GLOBAL, + /** + * 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) { GLOBAL -> Value.GLOBAL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { GLOBAL -> Known.GLOBAL else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Global && + name == other.name && + type == other.type && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(name, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Global{name=$name, type=$type, additionalProperties=$additionalProperties}" } } /** JSON schema for the function's parameters and return type */ - @JsonDeserialize(builder = FunctionSchema.Builder::class) - @NoAutoDetect class FunctionSchema + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val parameters: JsonValue?, - private val returns: JsonValue?, - private val additionalProperties: Map, + private val parameters: JsonValue, + private val returns: JsonValue, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("parameters") @ExcludeMissing parameters: JsonValue = JsonMissing.of(), + @JsonProperty("returns") @ExcludeMissing returns: JsonValue = JsonMissing.of(), + ) : this(parameters, returns, mutableMapOf()) + + @JsonProperty("parameters") @ExcludeMissing fun _parameters(): JsonValue = parameters - @JsonProperty("parameters") fun parameters(): JsonValue? = parameters + @JsonProperty("returns") @ExcludeMissing fun _returns(): JsonValue = returns - @JsonProperty("returns") fun returns(): JsonValue? = returns + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionSchema && - this.parameters == other.parameters && - this.returns == other.returns && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - parameters, - returns, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "FunctionSchema{parameters=$parameters, returns=$returns, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [FunctionSchema]. */ fun builder() = Builder() } - class Builder { + /** A builder for [FunctionSchema]. */ + class Builder internal constructor() { - private var parameters: JsonValue? = null - private var returns: JsonValue? = null + private var parameters: JsonValue = JsonMissing.of() + private var returns: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(functionSchema: FunctionSchema) = apply { - this.parameters = functionSchema.parameters - this.returns = functionSchema.returns - additionalProperties(functionSchema.additionalProperties) + parameters = functionSchema.parameters + returns = functionSchema.returns + additionalProperties = functionSchema.additionalProperties.toMutableMap() } - @JsonProperty("parameters") fun parameters(parameters: JsonValue) = apply { this.parameters = parameters } - @JsonProperty("returns") fun returns(returns: JsonValue) = apply { this.returns = returns } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FunctionSchema]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): FunctionSchema = - FunctionSchema( - parameters, - returns, - additionalProperties.toUnmodifiable(), - ) + FunctionSchema(parameters, returns, additionalProperties.toMutableMap()) } - } - class FunctionType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): FunctionSchema = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = 0 override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is FunctionType && this.value == other.value + return other is FunctionSchema && + parameters == other.parameters && + returns == other.returns && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash(parameters, returns, additionalProperties) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "FunctionSchema{parameters=$parameters, returns=$returns, additionalProperties=$additionalProperties}" + } + + class FunctionType @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 { - val LLM = FunctionType(JsonField.of("llm")) + val LLM = of("llm") - val SCORER = FunctionType(JsonField.of("scorer")) + val SCORER = of("scorer") - val TASK = FunctionType(JsonField.of("task")) + val TASK = of("task") - val TOOL = FunctionType(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = FunctionType(JsonField.of(value)) } + /** An enum containing [FunctionType]'s known values. */ enum class Known { LLM, SCORER, @@ -1962,14 +3757,33 @@ constructor( TOOL, } + /** + * An enum containing [FunctionType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [FunctionType] 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 { LLM, SCORER, TASK, TOOL, + /** + * An enum member indicating that [FunctionType] 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) { LLM -> Value.LLM @@ -1979,6 +3793,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { LLM -> Known.LLM @@ -1988,233 +3811,325 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown FunctionType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): FunctionType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FunctionType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } - @JsonDeserialize(builder = Origin.Builder::class) - @NoAutoDetect class Origin + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val objectType: ObjectType?, - private val objectId: String?, - private val internal_: Boolean?, - private val additionalProperties: Map, + private val objectId: JsonField, + private val objectType: JsonField, + private val internal_: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("internal") + @ExcludeMissing + internal_: JsonField = JsonMissing.of(), + ) : this(objectId, objectType, internal_, mutableMapOf()) - /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + /** + * Id of the object the function is originating from + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** Id of the object the function is originating from */ - @JsonProperty("object_id") fun objectId(): String? = objectId + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") /** * The function exists for internal purposes and should not be displayed in the list of * functions. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - @JsonProperty("internal") fun internal_(): Boolean? = internal_ + fun internal_(): Boolean? = internal_.getNullable("internal") - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [internal_]. + * + * Unlike [internal_], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("internal") @ExcludeMissing fun _internal_(): JsonField = internal_ - return other is Origin && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.internal_ == other.internal_ && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectType, - objectId, - internal_, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Origin{objectType=$objectType, objectId=$objectId, internal_=$internal_, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Origin]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Origin]. */ + class Builder internal constructor() { - private var objectType: ObjectType? = null - private var objectId: String? = null - private var internal_: Boolean? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var internal_: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(origin: Origin) = apply { - this.objectType = origin.objectType - this.objectId = origin.objectId - this.internal_ = origin.internal_ - additionalProperties(origin.additionalProperties) + objectId = origin.objectId + objectType = origin.objectType + internal_ = origin.internal_ + additionalProperties = origin.additionalProperties.toMutableMap() } + /** Id of the object the function is originating from */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) - /** Id of the object the function is originating from */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } /** * The function exists for internal purposes and should not be displayed in the list of * functions. */ - @JsonProperty("internal") - fun internal_(internal_: Boolean) = apply { this.internal_ = internal_ } + fun internal_(internal_: Boolean?) = internal_(JsonField.ofNullable(internal_)) + + /** + * Alias for [Builder.internal_]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun internal_(internal_: Boolean) = internal_(internal_ as Boolean?) + + /** + * Sets [Builder.internal_] to an arbitrary JSON value. + * + * You should usually call [Builder.internal_] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun internal_(internal_: JsonField) = apply { this.internal_ = internal_ } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Origin]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Origin = Origin( - checkNotNull(objectType) { "`objectType` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), internal_, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is ObjectType && this.value == other.value + fun validate(): Origin = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val EXPERIMENT = ObjectType(JsonField.of("experiment")) - - val DATASET = ObjectType(JsonField.of("dataset")) - - val PROMPT = ObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) - - val GROUP = ObjectType(JsonField.of("group")) - - val ROLE = ObjectType(JsonField.of("role")) - - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + objectId() + objectType().validate() + internal_() + validated = true + } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (internal_.asKnown() == null) 0 else 1) - fun of(value: String) = ObjectType(JsonField.of(value)) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + return other is Origin && + objectId == other.objectId && + objectType == other.objectType && + internal_ == other.internal_ && + additionalProperties == other.additionalProperties + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + private val hashCode: Int by lazy { + Objects.hash(objectId, objectType, internal_, additionalProperties) + } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + override fun hashCode(): Int = hashCode - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } + override fun toString() = + "Origin{objectId=$objectId, objectType=$objectType, internal_=$internal_, additionalProperties=$additionalProperties}" + } - fun asString(): String = _value().asStringOrThrow() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is FunctionReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "FunctionReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionRetrieveParams.kt index cd7aba68..cb78568f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionRetrieveParams.kt @@ -2,125 +2,189 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a function object by its id */ class FunctionRetrieveParams -constructor( - private val functionId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val functionId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun functionId(): String = functionId + /** Function id */ + fun functionId(): String? = functionId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> functionId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): FunctionRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FunctionRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [FunctionRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var functionId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(functionRetrieveParams: FunctionRetrieveParams) = apply { + functionId = functionRetrieveParams.functionId + additionalHeaders = functionRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = functionRetrieveParams.additionalQueryParams.toBuilder() } - return other is FunctionRetrieveParams && - this.functionId == other.functionId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Function id */ + fun functionId(functionId: String?) = apply { this.functionId = functionId } - override fun hashCode(): Int { - return Objects.hash( - functionId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "FunctionRetrieveParams{functionId=$functionId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var functionId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(functionRetrieveParams: FunctionRetrieveParams) = apply { - this.functionId = functionRetrieveParams.functionId - additionalQueryParams(functionRetrieveParams.additionalQueryParams) - additionalHeaders(functionRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Function id */ - fun functionId(functionId: String) = apply { this.functionId = functionId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [FunctionRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): FunctionRetrieveParams = FunctionRetrieveParams( - checkNotNull(functionId) { "`functionId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + functionId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> functionId ?: "" + 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 FunctionRetrieveParams && + functionId == other.functionId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(functionId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "FunctionRetrieveParams{functionId=$functionId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionToolChoice.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionToolChoice.kt deleted file mode 100644 index 90de4882..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionToolChoice.kt +++ /dev/null @@ -1,104 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import java.util.Objects - -@JsonDeserialize(builder = FunctionToolChoice.Builder::class) -@NoAutoDetect -class FunctionToolChoice -private constructor( - private val name: JsonField, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun name(): String = name.getRequired("name") - - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): FunctionToolChoice = apply { - if (!validated) { - name() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionToolChoice && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(name, additionalProperties) - } - return hashCode - } - - override fun toString() = - "FunctionToolChoice{name=$name, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var name: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(functionToolChoice: FunctionToolChoice) = apply { - this.name = functionToolChoice.name - additionalProperties(functionToolChoice.additionalProperties) - } - - fun name(name: String) = name(JsonField.of(name)) - - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): FunctionToolChoice = - FunctionToolChoice(name, additionalProperties.toUnmodifiable()) - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionUpdateParams.kt index dc64731c..3480e71b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/FunctionUpdateParams.kt @@ -9,9 +9,14 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.braintrustdata.api.models.CodeBundle.* import com.fasterxml.jackson.annotation.JsonAnyGetter @@ -25,366 +30,692 @@ 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 +/** + * Partially update a function object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class FunctionUpdateParams -constructor( - private val functionId: String, - private val description: String?, - private val functionData: FunctionData?, - private val name: String?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun functionId(): String = functionId - - fun description(): String? = description - - fun functionData(): FunctionData? = functionData - - fun name(): String? = name - - fun promptData(): PromptData? = promptData - - fun tags(): List? = tags - - internal fun getBody(): FunctionUpdateBody { - return FunctionUpdateBody( - description, - functionData, - name, - promptData, - tags, - additionalBodyProperties, - ) - } +private constructor( + private val functionId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Function id */ + fun functionId(): String? = functionId + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionData(): FunctionData? = body.functionData() + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = body.promptData() + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = body.tags() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [functionData]. + * + * Unlike [functionData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionData(): JsonField = body._functionData() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _promptData(): JsonField = body._promptData() + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tags(): JsonField> = body._tags() + + 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 - internal fun getQueryParams(): Map> = additionalQueryParams + fun toBuilder() = Builder().from(this) - internal fun getHeaders(): Map> = additionalHeaders + companion object { - fun getPathParam(index: Int): String { - return when (index) { - 0 -> functionId - else -> "" - } + fun none(): FunctionUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FunctionUpdateParams]. */ + fun builder() = Builder() } - @JsonDeserialize(builder = FunctionUpdateBody.Builder::class) - @NoAutoDetect - class FunctionUpdateBody - internal constructor( - private val description: String?, - private val functionData: FunctionData?, - private val name: String?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalProperties: Map, - ) { + /** A builder for [FunctionUpdateParams]. */ + class Builder internal constructor() { + + private var functionId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var hashCode: Int = 0 + internal fun from(functionUpdateParams: FunctionUpdateParams) = apply { + functionId = functionUpdateParams.functionId + body = functionUpdateParams.body.toBuilder() + additionalHeaders = functionUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = functionUpdateParams.additionalQueryParams.toBuilder() + } + + /** Function id */ + fun functionId(functionId: String?) = apply { this.functionId = functionId } + + /** + * 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: + * - [description] + * - [functionData] + * - [name] + * - [promptData] + * - [tags] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Textual description of the prompt */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + fun functionData(functionData: FunctionData?) = apply { body.functionData(functionData) } + + /** + * Sets [Builder.functionData] to an arbitrary JSON value. + * + * You should usually call [Builder.functionData] with a well-typed [FunctionData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionData(functionData: JsonField) = apply { + body.functionData(functionData) + } + + /** Alias for calling [functionData] with `FunctionData.ofPrompt(prompt)`. */ + fun functionData(prompt: FunctionData.Prompt) = apply { body.functionData(prompt) } - @JsonProperty("function_data") fun functionData(): FunctionData? = functionData + /** Alias for calling [functionData] with `FunctionData.ofCode(code)`. */ + fun functionData(code: FunctionData.Code) = apply { body.functionData(code) } + + /** Alias for calling [functionData] with `FunctionData.ofGlobal(global)`. */ + fun functionData(global: FunctionData.Global) = apply { body.functionData(global) } /** Name of the prompt */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") fun promptData(): PromptData? = promptData + fun promptData(promptData: PromptData?) = apply { body.promptData(promptData) } + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { body.promptData(promptData) } /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(): List? = tags + fun tags(tags: List?) = apply { body.tags(tags) } + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { body.tags(tags) } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { body.addTag(tag) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is FunctionUpdateBody && - this.description == other.description && - this.functionData == other.functionData && - this.name == other.name && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - description, - functionData, - name, - promptData, - tags, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "FunctionUpdateBody{description=$description, functionData=$functionData, name=$name, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var description: String? = null - private var functionData: FunctionData? = null - private var name: String? = null - private var promptData: PromptData? = null - private var tags: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(functionUpdateBody: FunctionUpdateBody) = apply { - this.description = functionUpdateBody.description - this.functionData = functionUpdateBody.functionData - this.name = functionUpdateBody.name - this.promptData = functionUpdateBody.promptData - this.tags = functionUpdateBody.tags - additionalProperties(functionUpdateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Textual description of the prompt */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - @JsonProperty("function_data") - fun functionData(functionData: FunctionData) = apply { - this.functionData = functionData - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Name of the prompt */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(tags: List) = apply { this.tags = tags } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): FunctionUpdateBody = - FunctionUpdateBody( - description, - functionData, - name, - promptData, - tags?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is FunctionUpdateParams && - this.functionId == other.functionId && - this.description == other.description && - this.functionData == other.functionData && - this.name == other.name && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [FunctionUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): FunctionUpdateParams = + FunctionUpdateParams( + functionId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - functionId, - description, - functionData, - name, - promptData, - tags, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "FunctionUpdateParams{functionId=$functionId, description=$description, functionData=$functionData, name=$name, promptData=$promptData, tags=$tags, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun _pathParam(index: Int): String = + when (index) { + 0 -> functionId ?: "" + else -> "" + } - fun toBuilder() = Builder().from(this) + override fun _headers(): Headers = additionalHeaders - companion object { + override fun _queryParams(): QueryParams = additionalQueryParams - fun builder() = Builder() - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val functionData: JsonField, + private val name: JsonField, + private val promptData: JsonField, + private val tags: JsonField>, + private val additionalProperties: MutableMap, + ) { - @NoAutoDetect - class Builder { + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("function_data") + @ExcludeMissing + functionData: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this(description, functionData, name, promptData, tags, mutableMapOf()) + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun functionData(): FunctionData? = functionData.getNullable("function_data") + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") + + /** + * 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 [functionData]. + * + * Unlike [functionData], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_data") + @ExcludeMissing + fun _functionData(): JsonField = functionData + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") + @ExcludeMissing + fun _promptData(): JsonField = promptData + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - private var functionId: String? = null - private var description: String? = null - private var functionData: FunctionData? = null - private var name: String? = null - private var promptData: PromptData? = null - private var tags: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - internal fun from(functionUpdateParams: FunctionUpdateParams) = apply { - this.functionId = functionUpdateParams.functionId - this.description = functionUpdateParams.description - this.functionData = functionUpdateParams.functionData - this.name = functionUpdateParams.name - this.promptData = functionUpdateParams.promptData - this.tags(functionUpdateParams.tags ?: listOf()) - additionalQueryParams(functionUpdateParams.additionalQueryParams) - additionalHeaders(functionUpdateParams.additionalHeaders) - additionalBodyProperties(functionUpdateParams.additionalBodyProperties) + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - /** Function id */ - fun functionId(functionId: String) = apply { this.functionId = functionId } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Textual description of the prompt */ - fun description(description: String) = apply { this.description = description } + private var description: JsonField = JsonMissing.of() + private var functionData: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun functionData(functionData: FunctionData) = apply { this.functionData = functionData } + internal fun from(body: Body) = apply { + description = body.description + functionData = body.functionData + name = body.name + promptData = body.promptData + tags = body.tags.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - fun functionData(prompt: FunctionData.Prompt) = apply { - this.functionData = FunctionData.ofPrompt(prompt) - } + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun functionData(code: FunctionData.Code) = apply { - this.functionData = FunctionData.ofCode(code) - } + fun functionData(functionData: FunctionData?) = + functionData(JsonField.ofNullable(functionData)) + + /** + * Sets [Builder.functionData] to an arbitrary JSON value. + * + * You should usually call [Builder.functionData] with a well-typed [FunctionData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionData(functionData: JsonField) = apply { + this.functionData = functionData + } - fun functionData(global: FunctionData.Global) = apply { - this.functionData = FunctionData.ofGlobal(global) - } + /** Alias for calling [functionData] with `FunctionData.ofPrompt(prompt)`. */ + fun functionData(prompt: FunctionData.Prompt) = + functionData(FunctionData.ofPrompt(prompt)) - fun functionData(nullableVariant: FunctionData.NullableVariant) = apply { - this.functionData = FunctionData.ofNullableVariant(nullableVariant) - } + /** Alias for calling [functionData] with `FunctionData.ofCode(code)`. */ + fun functionData(code: FunctionData.Code) = functionData(FunctionData.ofCode(code)) - /** Name of the prompt */ - fun name(name: String) = apply { this.name = name } + /** Alias for calling [functionData] with `FunctionData.ofGlobal(global)`. */ + fun functionData(global: FunctionData.Global) = + functionData(FunctionData.ofGlobal(global)) - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + /** Name of the prompt */ + fun name(name: String?) = name(JsonField.ofNullable(name)) - /** A list of tags for the prompt */ - fun tags(tags: List) = apply { - this.tags.clear() - this.tags.addAll(tags) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** A list of tags for the prompt */ - fun addTag(tag: String) = apply { this.tags.add(tag) } + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { + this.promptData = promptData + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = + (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body( + description, + functionData, + name, + promptData, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + description() + functionData()?.validate() + name() + promptData()?.validate() + tags() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (description.asKnown() == null) 0 else 1) + + (functionData.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (promptData.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + description == other.description && + functionData == other.functionData && + name == other.name && + promptData == other.promptData && + tags == other.tags && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(description, functionData, name, promptData, tags, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): FunctionUpdateParams = - FunctionUpdateParams( - checkNotNull(functionId) { "`functionId` is required but was not set" }, - description, - functionData, - name, - promptData, - if (tags.size == 0) null else tags.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{description=$description, functionData=$functionData, name=$name, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" } @JsonDeserialize(using = FunctionData.Deserializer::class) @@ -394,92 +725,110 @@ constructor( private val prompt: Prompt? = null, private val code: Code? = null, private val global: Global? = null, - private val nullableVariant: NullableVariant? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun prompt(): Prompt? = prompt fun code(): Code? = code fun global(): Global? = global - fun nullableVariant(): NullableVariant? = nullableVariant - fun isPrompt(): Boolean = prompt != null fun isCode(): Boolean = code != null fun isGlobal(): Boolean = global != null - fun isNullableVariant(): Boolean = nullableVariant != null - fun asPrompt(): Prompt = prompt.getOrThrow("prompt") fun asCode(): Code = code.getOrThrow("code") fun asGlobal(): Global = global.getOrThrow("global") - fun asNullableVariant(): NullableVariant = nullableVariant.getOrThrow("nullableVariant") - fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { prompt != null -> visitor.visitPrompt(prompt) code != null -> visitor.visitCode(code) global != null -> visitor.visitGlobal(global) - nullableVariant != null -> visitor.visitNullableVariant(nullableVariant) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): FunctionData = apply { - if (!validated) { - if (prompt == null && code == null && global == null && nullableVariant == null) { - throw BraintrustInvalidDataException("Unknown FunctionData: $_json") - } - prompt?.validate() - code?.validate() - global?.validate() - nullableVariant?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) { + prompt.validate() + } + + override fun visitCode(code: Code) { + code.validate() + } + + override fun visitGlobal(global: Global) { + global.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitPrompt(prompt: Prompt) = prompt.validity() + + override fun visitCode(code: Code) = code.validity() + + override fun visitGlobal(global: Global) = global.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is FunctionData && - this.prompt == other.prompt && - this.code == other.code && - this.global == other.global && - this.nullableVariant == other.nullableVariant + prompt == other.prompt && + code == other.code && + global == other.global } - override fun hashCode(): Int { - return Objects.hash( - prompt, - code, - global, - nullableVariant, - ) - } + override fun hashCode(): Int = Objects.hash(prompt, code, global) - override fun toString(): String { - return when { + override fun toString(): String = + when { prompt != null -> "FunctionData{prompt=$prompt}" code != null -> "FunctionData{code=$code}" global != null -> "FunctionData{global=$global}" - nullableVariant != null -> "FunctionData{nullableVariant=$nullableVariant}" _json != null -> "FunctionData{_unknown=$_json}" else -> throw IllegalStateException("Invalid FunctionData") } - } companion object { @@ -488,11 +837,12 @@ constructor( fun ofCode(code: Code) = FunctionData(code = code) fun ofGlobal(global: Global) = FunctionData(global = global) - - fun ofNullableVariant(nullableVariant: NullableVariant) = - FunctionData(nullableVariant = nullableVariant) } + /** + * An interface that defines how to map each variant of [FunctionData] to a value of type + * [T]. + */ interface Visitor { fun visitPrompt(prompt: Prompt): T @@ -501,134 +851,151 @@ constructor( fun visitGlobal(global: Global): T - fun visitNullableVariant(nullableVariant: NullableVariant): T - + /** + * Maps an unknown variant of [FunctionData] to a value of type [T]. + * + * An instance of [FunctionData] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown FunctionData: $json") } } - class Deserializer : BaseDeserializer(FunctionData::class) { + internal class Deserializer : BaseDeserializer(FunctionData::class) { override fun ObjectCodec.deserialize(node: JsonNode): FunctionData { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(prompt = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(code = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(global = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionData(nullableVariant = it, _json = json) - } - return FunctionData(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(prompt = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(code = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionData(global = 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 -> FunctionData(_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() + } } } - class Serializer : BaseSerializer(FunctionData::class) { + internal class Serializer : BaseSerializer(FunctionData::class) { override fun serialize( value: FunctionData, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.prompt != null -> generator.writeObject(value.prompt) value.code != null -> generator.writeObject(value.code) value.global != null -> generator.writeObject(value.global) - value.nullableVariant != null -> generator.writeObject(value.nullableVariant) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid FunctionData") } } } - @JsonDeserialize(builder = Prompt.Builder::class) - @NoAutoDetect class Prompt + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of() + ) : this(type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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 = additionalProperties - - fun validate(): Prompt = apply { - if (!validated) { - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Prompt && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(type, additionalProperties) - } - return hashCode - } - - override fun toString() = - "Prompt{type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Prompt]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Prompt]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(prompt: Prompt) = apply { - this.type = prompt.type - additionalProperties(prompt.additionalProperties) + type = prompt.type + additionalProperties = prompt.additionalProperties.toMutableMap() } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -636,159 +1003,314 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Prompt = Prompt(type, additionalProperties.toUnmodifiable()) - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns an immutable instance of [Prompt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Prompt = + Prompt(checkRequired("type", type), additionalProperties.toMutableMap()) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Type && this.value == other.value + fun validate(): Prompt = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() + type().validate() + validated = true + } - override fun toString() = value.toString() + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (type.asKnown()?.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 { - val PROMPT = Type(JsonField.of("prompt")) + val PROMPT = of("prompt") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - PROMPT, + PROMPT } + /** + * 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 { PROMPT, + /** + * 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) { PROMPT -> Value.PROMPT 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { PROMPT -> Known.PROMPT else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Code.Builder::class) - @NoAutoDetect - class Code - private constructor( - private val type: JsonField, - private val data: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun data(): Data = data.getRequired("data") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("data") @ExcludeMissing fun _data() = data + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Code = apply { - if (!validated) { - type() - data() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Code && - this.type == other.type && - this.data == other.data && - this.additionalProperties == other.additionalProperties + return other is Prompt && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - data, - additionalProperties, - ) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(type, additionalProperties) } + + override fun hashCode(): Int = hashCode override fun toString() = - "Code{type=$type, data=$data, additionalProperties=$additionalProperties}" + "Prompt{type=$type, additionalProperties=$additionalProperties}" + } + + class Code + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val data: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(data, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 BraintrustInvalidDataException 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 [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 [Code]. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Code]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var data: JsonField = JsonMissing.of() + private var data: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(code: Code) = apply { - this.type = code.type - this.data = code.data - additionalProperties(code.additionalProperties) + data = code.data + type = code.type + additionalProperties = code.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun data(data: Data) = data(JsonField.of(data)) - @JsonProperty("data") - @ExcludeMissing + /** + * 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.ofBundle(bundle)`. */ + fun data(bundle: Data.Bundle) = data(Data.ofBundle(bundle)) + + /** Alias for calling [data] with `Data.ofInline(inline)`. */ + fun data(inline: Data.Inline) = data(Data.ofInline(inline)) + + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -796,14 +1318,64 @@ constructor( 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 [Code]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .data() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Code = Code( - type, - data, - additionalProperties.toUnmodifiable(), + checkRequired("data", data), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Code = apply { + if (validated) { + return@apply + } + + data().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (data.asKnown()?.validity() ?: 0) + (type.asKnown()?.validity() ?: 0) + @JsonDeserialize(using = Data.Deserializer::class) @JsonSerialize(using = Data.Serializer::class) class Data @@ -813,8 +1385,6 @@ constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun bundle(): Bundle? = bundle fun inline(): Inline? = inline @@ -829,46 +1399,76 @@ constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { bundle != null -> visitor.visitBundle(bundle) inline != null -> visitor.visitInline(inline) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Data = apply { - if (!validated) { - if (bundle == null && inline == null) { - throw BraintrustInvalidDataException("Unknown Data: $_json") - } - inline?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) { + bundle.validate() + } + + override fun visitInline(inline: Inline) { + inline.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBundle(bundle: Bundle) = bundle.validity() + + override fun visitInline(inline: Inline) = inline.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Data && - this.bundle == other.bundle && - this.inline == other.inline + return other is Data && bundle == other.bundle && inline == other.inline } - override fun hashCode(): Int { - return Objects.hash(bundle, inline) - } + override fun hashCode(): Int = Objects.hash(bundle, inline) - override fun toString(): String { - return when { + override fun toString(): String = + when { bundle != null -> "Data{bundle=$bundle}" inline != null -> "Data{inline=$inline}" _json != null -> "Data{_unknown=$_json}" else -> throw IllegalStateException("Invalid Data") } - } companion object { @@ -877,39 +1477,68 @@ constructor( fun ofInline(inline: Inline) = Data(inline = inline) } + /** + * An interface that defines how to map each variant of [Data] to a value of type + * [T]. + */ interface Visitor { fun visitBundle(bundle: Bundle): T fun visitInline(inline: Inline): 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Data: $json") } } - class Deserializer : BaseDeserializer(Data::class) { + internal class Deserializer : BaseDeserializer(Data::class) { override fun ObjectCodec.deserialize(node: JsonNode): Data { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Data(bundle = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Data(inline = it, _json = json) - } - return Data(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Data(bundle = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Data(inline = 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() + } } } - class Serializer : BaseSerializer(Data::class) { + internal class Serializer : BaseSerializer(Data::class) { override fun serialize( value: Data, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.bundle != null -> generator.writeObject(value.bundle) @@ -920,474 +1549,840 @@ constructor( } } - @JsonDeserialize(builder = Bundle.Builder::class) - @NoAutoDetect class Bundle + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val runtimeContext: JsonField, - private val location: JsonField, private val bundleId: JsonField, + private val location: JsonField, + private val runtimeContext: JsonField, private val preview: JsonField, private val type: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun runtimeContext(): RuntimeContext = - runtimeContext.getRequired("runtime_context") - - fun location(): Location = location.getRequired("location") - - fun bundleId(): String = bundleId.getRequired("bundle_id") - - /** A preview of the code */ - fun preview(): String? = preview.getNullable("preview") - - fun type(): Type = type.getRequired("type") + @JsonCreator + private constructor( + @JsonProperty("bundle_id") + @ExcludeMissing + bundleId: JsonField = JsonMissing.of(), + @JsonProperty("location") + @ExcludeMissing + location: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("preview") + @ExcludeMissing + preview: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(bundleId, location, runtimeContext, preview, type, mutableMapOf()) fun toCodeBundle(): CodeBundle = CodeBundle.builder() - .runtimeContext(runtimeContext) - .location(location) .bundleId(bundleId) + .location(location) + .runtimeContext(runtimeContext) .preview(preview) .build() - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + /** + * @throws BraintrustInvalidDataException 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 bundleId(): String = bundleId.getRequired("bundle_id") - @JsonProperty("location") @ExcludeMissing fun _location() = location + /** + * @throws BraintrustInvalidDataException 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 location(): CodeBundle.Location = location.getRequired("location") + + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): CodeBundle.RuntimeContext = + runtimeContext.getRequired("runtime_context") - @JsonProperty("bundle_id") @ExcludeMissing fun _bundleId() = bundleId + /** + * A preview of the code + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun preview(): String? = preview.getNullable("preview") - /** A preview of the code */ - @JsonProperty("preview") @ExcludeMissing fun _preview() = preview + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * Returns the raw JSON value of [bundleId]. + * + * Unlike [bundleId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("bundle_id") + @ExcludeMissing + fun _bundleId(): JsonField = bundleId + + /** + * 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 [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * Returns the raw JSON value of [preview]. + * + * Unlike [preview], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("preview") + @ExcludeMissing + fun _preview(): JsonField = preview + + /** + * 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 = additionalProperties - - fun validate(): Bundle = apply { - if (!validated) { - runtimeContext().validate() - location() - bundleId() - preview() - type() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Bundle && - this.runtimeContext == other.runtimeContext && - this.location == other.location && - this.bundleId == other.bundleId && - this.preview == other.preview && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtimeContext, - location, - bundleId, - preview, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Bundle{runtimeContext=$runtimeContext, location=$location, bundleId=$bundleId, preview=$preview, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Bundle]. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Bundle]. */ + class Builder internal constructor() { - private var runtimeContext: JsonField = JsonMissing.of() - private var location: JsonField = JsonMissing.of() - private var bundleId: JsonField = JsonMissing.of() + private var bundleId: JsonField? = null + private var location: JsonField? = null + private var runtimeContext: JsonField? = null private var preview: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(bundle: Bundle) = apply { - this.runtimeContext = bundle.runtimeContext - this.location = bundle.location - this.bundleId = bundle.bundleId - this.preview = bundle.preview - this.type = bundle.type - additionalProperties(bundle.additionalProperties) + bundleId = bundle.bundleId + location = bundle.location + runtimeContext = bundle.runtimeContext + preview = bundle.preview + type = bundle.type + additionalProperties = bundle.additionalProperties.toMutableMap() } - fun runtimeContext(runtimeContext: RuntimeContext) = - runtimeContext(JsonField.of(runtimeContext)) + fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - @JsonProperty("runtime_context") - @ExcludeMissing - fun runtimeContext(runtimeContext: JsonField) = apply { - this.runtimeContext = runtimeContext + /** + * Sets [Builder.bundleId] to an arbitrary JSON value. + * + * You should usually call [Builder.bundleId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun bundleId(bundleId: JsonField) = apply { + this.bundleId = bundleId } - fun location(location: Location) = location(JsonField.of(location)) - - @JsonProperty("location") - @ExcludeMissing - fun location(location: JsonField) = apply { + fun location(location: CodeBundle.Location) = + location(JsonField.of(location)) + + /** + * Sets [Builder.location] to an arbitrary JSON value. + * + * You should usually call [Builder.location] with a well-typed + * [CodeBundle.Location] 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 } - fun bundleId(bundleId: String) = bundleId(JsonField.of(bundleId)) - - @JsonProperty("bundle_id") - @ExcludeMissing - fun bundleId(bundleId: JsonField) = apply { - this.bundleId = bundleId - } + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofExperiment(experiment)`. + */ + fun location(experiment: CodeBundle.Location.Experiment) = + location(CodeBundle.Location.ofExperiment(experiment)) + + /** + * Alias for calling [location] with + * `CodeBundle.Location.ofFunction(function)`. + */ + fun location(function: CodeBundle.Location.Function) = + location(CodeBundle.Location.ofFunction(function)) + + fun runtimeContext(runtimeContext: CodeBundle.RuntimeContext) = + runtimeContext(JsonField.of(runtimeContext)) - /** A preview of the code */ - fun preview(preview: String) = preview(JsonField.of(preview)) + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [CodeBundle.RuntimeContext] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun runtimeContext(runtimeContext: JsonField) = + apply { + this.runtimeContext = runtimeContext + } /** A preview of the code */ - @JsonProperty("preview") - @ExcludeMissing + fun preview(preview: String?) = preview(JsonField.ofNullable(preview)) + + /** + * Sets [Builder.preview] to an arbitrary JSON value. + * + * You should usually call [Builder.preview] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun preview(preview: JsonField) = apply { this.preview = preview } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Bundle]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .bundleId() + * .location() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Bundle = Bundle( - runtimeContext, - location, - bundleId, + checkRequired("bundleId", bundleId), + checkRequired("location", location), + checkRequired("runtimeContext", runtimeContext), preview, - type, - additionalProperties.toUnmodifiable(), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Bundle = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + bundleId() + location().validate() + runtimeContext().validate() + preview() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (bundleId.asKnown() == null) 0 else 1) + + (location.asKnown()?.validity() ?: 0) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (if (preview.asKnown() == null) 0 else 1) + + (type.asKnown()?.validity() ?: 0) - override fun toString() = value.toString() + 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 { - val BUNDLE = Type(JsonField.of("bundle")) + val BUNDLE = of("bundle") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - BUNDLE, + BUNDLE } + /** + * 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 { BUNDLE, + /** + * 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) { BUNDLE -> Value.BUNDLE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { BUNDLE -> Known.BUNDLE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - - @JsonDeserialize(builder = Inline.Builder::class) - @NoAutoDetect - class Inline - private constructor( - private val type: JsonField, - private val runtimeContext: JsonField, - private val code: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - private var hashCode: Int = 0 + private var validated: Boolean = false - fun type(): Type = type.getRequired("type") + fun validate(): Type = apply { + if (validated) { + return@apply + } - fun runtimeContext(): RuntimeContext = - runtimeContext.getRequired("runtime_context") + known() + validated = true + } - fun code(): String = code.getRequired("code") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("runtime_context") - @ExcludeMissing - fun _runtimeContext() = runtimeContext + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("code") @ExcludeMissing fun _code() = code + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Inline = apply { - if (!validated) { - type() - runtimeContext().validate() - code() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Inline && - this.type == other.type && - this.runtimeContext == other.runtimeContext && - this.code == other.code && - this.additionalProperties == other.additionalProperties + return other is Bundle && + bundleId == other.bundleId && + location == other.location && + runtimeContext == other.runtimeContext && + preview == other.preview && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - runtimeContext, - code, - additionalProperties, - ) - } - return hashCode + private val hashCode: Int by lazy { + Objects.hash( + bundleId, + location, + runtimeContext, + preview, + type, + additionalProperties, + ) } + override fun hashCode(): Int = hashCode + override fun toString() = - "Inline{type=$type, runtimeContext=$runtimeContext, code=$code, additionalProperties=$additionalProperties}" + "Bundle{bundleId=$bundleId, location=$location, runtimeContext=$runtimeContext, preview=$preview, type=$type, additionalProperties=$additionalProperties}" + } + + class Inline + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val code: JsonField, + private val runtimeContext: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("code") + @ExcludeMissing + code: JsonField = JsonMissing.of(), + @JsonProperty("runtime_context") + @ExcludeMissing + runtimeContext: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(code, runtimeContext, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 code(): String = code.getRequired("code") + + /** + * @throws BraintrustInvalidDataException 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 runtimeContext(): RuntimeContext = + runtimeContext.getRequired("runtime_context") + + /** + * @throws BraintrustInvalidDataException 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 [code]. + * + * Unlike [code], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("code") @ExcludeMissing fun _code(): JsonField = code + + /** + * Returns the raw JSON value of [runtimeContext]. + * + * Unlike [runtimeContext], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime_context") + @ExcludeMissing + fun _runtimeContext(): JsonField = runtimeContext + + /** + * 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 [Inline]. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Inline]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var runtimeContext: JsonField = JsonMissing.of() - private var code: JsonField = JsonMissing.of() + private var code: JsonField? = null + private var runtimeContext: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inline: Inline) = apply { - this.type = inline.type - this.runtimeContext = inline.runtimeContext - this.code = inline.code - additionalProperties(inline.additionalProperties) + code = inline.code + runtimeContext = inline.runtimeContext + type = inline.type + additionalProperties = inline.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) + fun code(code: String) = code(JsonField.of(code)) - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } + /** + * Sets [Builder.code] to an arbitrary JSON value. + * + * You should usually call [Builder.code] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun code(code: JsonField) = apply { this.code = code } fun runtimeContext(runtimeContext: RuntimeContext) = runtimeContext(JsonField.of(runtimeContext)) - @JsonProperty("runtime_context") - @ExcludeMissing + /** + * Sets [Builder.runtimeContext] to an arbitrary JSON value. + * + * You should usually call [Builder.runtimeContext] with a well-typed + * [RuntimeContext] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ fun runtimeContext(runtimeContext: JsonField) = apply { this.runtimeContext = runtimeContext } - fun code(code: String) = code(JsonField.of(code)) + fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("code") - @ExcludeMissing - fun code(code: JsonField) = apply { this.code = code } + /** + * 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Inline]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .code() + * .runtimeContext() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Inline = Inline( - type, - runtimeContext, - code, - additionalProperties.toUnmodifiable(), + checkRequired("code", code), + checkRequired("runtimeContext", runtimeContext), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = RuntimeContext.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): Inline = apply { + if (validated) { + return@apply + } + + code() + runtimeContext().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (code.asKnown() == null) 0 else 1) + + (runtimeContext.asKnown()?.validity() ?: 0) + + (type.asKnown()?.validity() ?: 0) + class RuntimeContext + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val runtime: JsonField, private val version: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("runtime") + @ExcludeMissing + runtime: JsonField = JsonMissing.of(), + @JsonProperty("version") + @ExcludeMissing + version: JsonField = JsonMissing.of(), + ) : this(runtime, version, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 runtime(): Runtime = runtime.getRequired("runtime") + /** + * @throws BraintrustInvalidDataException 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 version(): String = version.getRequired("version") - @JsonProperty("runtime") @ExcludeMissing fun _runtime() = runtime + /** + * Returns the raw JSON value of [runtime]. + * + * Unlike [runtime], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("runtime") + @ExcludeMissing + fun _runtime(): JsonField = runtime + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("version") + @ExcludeMissing + fun _version(): JsonField = version - @JsonProperty("version") @ExcludeMissing fun _version() = version + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): RuntimeContext = apply { - if (!validated) { - runtime() - version() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RuntimeContext && - this.runtime == other.runtime && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - runtime, - version, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of + * [RuntimeContext]. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RuntimeContext]. */ + class Builder internal constructor() { - private var runtime: JsonField = JsonMissing.of() - private var version: JsonField = JsonMissing.of() + private var runtime: JsonField? = null + private var version: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(runtimeContext: RuntimeContext) = apply { - this.runtime = runtimeContext.runtime - this.version = runtimeContext.version - additionalProperties(runtimeContext.additionalProperties) + runtime = runtimeContext.runtime + version = runtimeContext.version + additionalProperties = + runtimeContext.additionalProperties.toMutableMap() } fun runtime(runtime: Runtime) = runtime(JsonField.of(runtime)) - @JsonProperty("runtime") - @ExcludeMissing + /** + * Sets [Builder.runtime] to an arbitrary JSON value. + * + * You should usually call [Builder.runtime] with a well-typed [Runtime] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun runtime(runtime: JsonField) = apply { this.runtime = runtime } fun version(version: String) = version(JsonField.of(version)) - @JsonProperty("version") - @ExcludeMissing + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun version(version: JsonField) = apply { this.version = version } @@ -1395,67 +2390,136 @@ constructor( fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RuntimeContext]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```kotlin + * .runtime() + * .version() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RuntimeContext = RuntimeContext( - runtime, - version, - additionalProperties.toUnmodifiable(), + checkRequired("runtime", runtime), + checkRequired("version", version), + additionalProperties.toMutableMap(), ) } - class Runtime - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): RuntimeContext = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + runtime().validate() + version() + validated = true + } - return other is Runtime && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (runtime.asKnown()?.validity() ?: 0) + + (if (version.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Runtime + @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 { - val NODE = Runtime(JsonField.of("node")) + val NODE = of("node") - val PYTHON = Runtime(JsonField.of("python")) + val PYTHON = of("python") fun of(value: String) = Runtime(JsonField.of(value)) } + /** An enum containing [Runtime]'s known values. */ enum class Known { NODE, PYTHON, } + /** + * An enum containing [Runtime]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Runtime] 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 { NODE, PYTHON, + /** + * An enum member indicating that [Runtime] 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) { NODE -> Value.NODE @@ -1463,6 +2527,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value + * is a not a known member. + */ fun known(): Known = when (this) { NODE -> Known.NODE @@ -1473,214 +2546,482 @@ constructor( ) } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Runtime = apply { + if (validated) { + return@apply + } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + 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 Runtime && 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 Type && this.value == other.value + return other is RuntimeContext && + runtime == other.runtime && + version == other.version && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash(runtime, version, additionalProperties) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "RuntimeContext{runtime=$runtime, version=$version, additionalProperties=$additionalProperties}" + } + + 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 { - val INLINE = Type(JsonField.of("inline")) + val INLINE = of("inline") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - INLINE, + INLINE } + /** + * 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 { INLINE, + /** + * 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) { INLINE -> Value.INLINE 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { INLINE -> Known.INLINE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + return other is Inline && + code == other.code && + runtimeContext == other.runtimeContext && + type == other.type && + additionalProperties == other.additionalProperties + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + private val hashCode: Int by lazy { + Objects.hash(code, runtimeContext, type, additionalProperties) } - return other is Type && this.value == other.value - } + override fun hashCode(): Int = hashCode - override fun hashCode() = value.hashCode() + override fun toString() = + "Inline{code=$code, runtimeContext=$runtimeContext, type=$type, additionalProperties=$additionalProperties}" + } + } - override fun toString() = value.toString() + 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 { - val CODE = Type(JsonField.of("code")) + val CODE = of("code") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - CODE, + CODE } + /** + * 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 { CODE, + /** + * 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) { CODE -> Value.CODE 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { CODE -> Known.CODE else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Global.Builder::class) - @NoAutoDetect - class Global - private constructor( - private val type: JsonField, - private val name: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun name(): String = name.getRequired("name") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("name") @ExcludeMissing fun _name() = name + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Global = apply { - if (!validated) { - type() - name() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Global && - this.type == other.type && - this.name == other.name && - this.additionalProperties == other.additionalProperties + return other is Code && + data == other.data && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - name, - additionalProperties, - ) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(data, type, additionalProperties) } + + override fun hashCode(): Int = hashCode override fun toString() = - "Global{type=$type, name=$name, additionalProperties=$additionalProperties}" + "Code{data=$data, type=$type, additionalProperties=$additionalProperties}" + } + + class Global + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [Global]. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Global]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var name: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(global: Global) = apply { - this.type = global.type - this.name = global.name - additionalProperties(global.additionalProperties) + name = global.name + type = global.type + additionalProperties = global.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -1688,138 +3029,222 @@ constructor( 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 [Global]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Global = Global( - type, - name, - additionalProperties.toUnmodifiable(), + checkRequired("name", name), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Global = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val GLOBAL = Type(JsonField.of("global")) + val GLOBAL = of("global") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - GLOBAL, + GLOBAL } + /** + * 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 { GLOBAL, + /** + * 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) { GLOBAL -> Value.GLOBAL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { GLOBAL -> Known.GLOBAL else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - - @JsonDeserialize(builder = NullableVariant.Builder::class) - @NoAutoDetect - class NullableVariant - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - private var hashCode: Int = 0 + private var validated: Boolean = false - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun validate(): Type = apply { + if (validated) { + return@apply + } - fun validate(): NullableVariant = apply { - if (!validated) { + known() validated = true } - } - fun toBuilder() = Builder().from(this) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - return other is NullableVariant && - this.additionalProperties == other.additionalProperties - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) + return other is Type && value == other.value } - return hashCode - } - - override fun toString() = "NullableVariant{additionalProperties=$additionalProperties}" - companion object { + override fun hashCode() = value.hashCode() - fun builder() = Builder() + override fun toString() = value.toString() } - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(nullableVariant: NullableVariant) = apply { - additionalProperties(nullableVariant.additionalProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + return other is Global && + name == other.name && + type == other.type && + additionalProperties == other.additionalProperties + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + private val hashCode: Int by lazy { Objects.hash(name, type, additionalProperties) } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = hashCode - fun build(): NullableVariant = - NullableVariant(additionalProperties.toUnmodifiable()) - } + override fun toString() = + "Global{name=$name, type=$type, additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is FunctionUpdateParams && + functionId == other.functionId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(functionId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "FunctionUpdateParams{functionId=$functionId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Group.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Group.kt index 54c6d717..2949db83 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Group.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Group.kt @@ -6,13 +6,16 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects /** @@ -20,195 +23,276 @@ import java.util.Objects * * Groups can consist of individual users, as well as a set of groups they inherit from */ -@JsonDeserialize(builder = Group.Builder::class) -@NoAutoDetect class Group +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, + private val name: JsonField, private val orgId: JsonField, - private val userId: JsonField, private val created: JsonField, - private val name: JsonField, - private val description: JsonField, private val deletedAt: JsonField, - private val memberUsers: JsonField>, + private val description: JsonField, private val memberGroups: JsonField>, - private val additionalProperties: Map, + private val memberUsers: JsonField>, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("member_groups") + @ExcludeMissing + memberGroups: JsonField> = JsonMissing.of(), + @JsonProperty("member_users") + @ExcludeMissing + memberUsers: JsonField> = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( + id, + name, + orgId, + created, + deletedAt, + description, + memberGroups, + memberUsers, + userId, + mutableMapOf(), + ) - /** Unique identifier for the group */ + /** + * Unique identifier for the group + * + * @throws BraintrustInvalidDataException 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") + /** + * Name of the group + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + /** * Unique id for the organization that the group belongs under * * It is forbidden to change the org after creating a group + * + * @throws BraintrustInvalidDataException 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 orgId(): String = orgId.getRequired("org_id") - /** Identifies the user who created the group */ - fun userId(): String? = userId.getNullable("user_id") - - /** Date of group creation */ + /** + * Date of group creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** Name of the group */ - fun name(): String = name.getRequired("name") - - /** Textual description of the group */ - fun description(): String? = description.getNullable("description") - - /** Date of group deletion, or null if the group is still active */ + /** + * Date of group deletion, or null if the group is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - /** Ids of users which belong to this group */ - fun memberUsers(): List? = memberUsers.getNullable("member_users") + /** + * Textual description of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") /** * Ids of the groups this group inherits from * * An inheriting group has all the users contained in its member groups, as well as all of their * inherited users + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun memberGroups(): List? = memberGroups.getNullable("member_groups") - /** Unique identifier for the group */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - /** - * Unique id for the organization that the group belongs under + * Ids of users which belong to this group * - * It is forbidden to change the org after creating a group + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId + fun memberUsers(): List? = memberUsers.getNullable("member_users") - /** Identifies the user who created the group */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + /** + * Identifies the user who created the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - /** Date of group creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * 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 - /** Name of the group */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Textual description of the group */ - @JsonProperty("description") @ExcludeMissing fun _description() = description + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId - /** Date of group deletion, or null if the group is still active */ - @JsonProperty("deleted_at") @ExcludeMissing fun _deletedAt() = deletedAt + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - /** Ids of users which belong to this group */ - @JsonProperty("member_users") @ExcludeMissing fun _memberUsers() = memberUsers + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt /** - * Ids of the groups this group inherits from + * Returns the raw JSON value of [description]. * - * An inheriting group has all the users contained in its member groups, as well as all of their - * inherited users + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("member_groups") @ExcludeMissing fun _memberGroups() = memberGroups + @JsonProperty("description") @ExcludeMissing fun _description(): JsonField = description - @JsonAnyGetter + /** + * Returns the raw JSON value of [memberGroups]. + * + * Unlike [memberGroups], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_groups") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Group = apply { - if (!validated) { - id() - orgId() - userId() - created() - name() - description() - deletedAt() - memberUsers() - memberGroups() - validated = true - } - } + fun _memberGroups(): JsonField> = memberGroups - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [memberUsers]. + * + * Unlike [memberUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_users") + @ExcludeMissing + fun _memberUsers(): JsonField> = memberUsers - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId - return other is Group && - this.id == other.id && - this.orgId == other.orgId && - this.userId == other.userId && - this.created == other.created && - this.name == other.name && - this.description == other.description && - this.deletedAt == other.deletedAt && - this.memberUsers == other.memberUsers && - this.memberGroups == other.memberGroups && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - orgId, - userId, - created, - name, - description, - deletedAt, - memberUsers, - memberGroups, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Group{id=$id, orgId=$orgId, userId=$userId, created=$created, name=$name, description=$description, deletedAt=$deletedAt, memberUsers=$memberUsers, memberGroups=$memberGroups, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Group]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .orgId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Group]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var orgId: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var orgId: JsonField? = null private var created: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() private var deletedAt: JsonField = JsonMissing.of() - private var memberUsers: JsonField> = JsonMissing.of() - private var memberGroups: JsonField> = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var memberGroups: JsonField>? = null + private var memberUsers: JsonField>? = null + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(group: Group) = apply { - this.id = group.id - this.orgId = group.orgId - this.userId = group.userId - this.created = group.created - this.name = group.name - this.description = group.description - this.deletedAt = group.deletedAt - this.memberUsers = group.memberUsers - this.memberGroups = group.memberGroups - additionalProperties(group.additionalProperties) + id = group.id + name = group.name + orgId = group.orgId + created = group.created + deletedAt = group.deletedAt + description = group.description + memberGroups = group.memberGroups.map { it.toMutableList() } + memberUsers = group.memberUsers.map { it.toMutableList() } + userId = group.userId + additionalProperties = group.additionalProperties.toMutableMap() } /** Unique identifier for the group */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the group */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } + + /** Name of the group */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } /** * Unique id for the organization that the group belongs under @@ -218,110 +302,244 @@ private constructor( fun orgId(orgId: String) = orgId(JsonField.of(orgId)) /** - * Unique id for the organization that the group belongs under + * Sets [Builder.orgId] to an arbitrary JSON value. * - * It is forbidden to change the org after creating a group + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("org_id") - @ExcludeMissing fun orgId(orgId: JsonField) = apply { this.orgId = orgId } - /** Identifies the user who created the group */ - fun userId(userId: String) = userId(JsonField.of(userId)) - - /** Identifies the user who created the group */ - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } - /** Date of group creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) - /** Date of group creation */ - @JsonProperty("created") - @ExcludeMissing + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } - /** Name of the group */ - fun name(name: String) = name(JsonField.of(name)) + /** Date of group deletion, or null if the group is still active */ + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) - /** Name of the group */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } /** Textual description of the group */ - fun description(description: String) = description(JsonField.of(description)) + fun description(description: String?) = description(JsonField.ofNullable(description)) - /** Textual description of the group */ - @JsonProperty("description") - @ExcludeMissing + /** + * 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 } - /** Date of group deletion, or null if the group is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = deletedAt(JsonField.of(deletedAt)) + /** + * Ids of the groups this group inherits from + * + * An inheriting group has all the users contained in its member groups, as well as all of + * their inherited users + */ + fun memberGroups(memberGroups: List?) = + memberGroups(JsonField.ofNullable(memberGroups)) - /** Date of group deletion, or null if the group is still active */ - @JsonProperty("deleted_at") - @ExcludeMissing - fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } + /** + * Sets [Builder.memberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.memberGroups] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberGroups(memberGroups: JsonField>) = apply { + this.memberGroups = memberGroups.map { it.toMutableList() } + } - /** Ids of users which belong to this group */ - fun memberUsers(memberUsers: List) = memberUsers(JsonField.of(memberUsers)) + /** + * Adds a single [String] to [memberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberGroup(memberGroup: String) = apply { + memberGroups = + (memberGroups ?: JsonField.of(mutableListOf())).also { + checkKnown("memberGroups", it).add(memberGroup) + } + } /** Ids of users which belong to this group */ - @JsonProperty("member_users") - @ExcludeMissing + fun memberUsers(memberUsers: List?) = memberUsers(JsonField.ofNullable(memberUsers)) + + /** + * Sets [Builder.memberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.memberUsers] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun memberUsers(memberUsers: JsonField>) = apply { - this.memberUsers = memberUsers + this.memberUsers = memberUsers.map { it.toMutableList() } } /** - * Ids of the groups this group inherits from + * Adds a single [String] to [memberUsers]. * - * An inheriting group has all the users contained in its member groups, as well as all of - * their inherited users + * @throws IllegalStateException if the field was previously set to a non-list. */ - fun memberGroups(memberGroups: List) = memberGroups(JsonField.of(memberGroups)) + fun addMemberUser(memberUser: String) = apply { + memberUsers = + (memberUsers ?: JsonField.of(mutableListOf())).also { + checkKnown("memberUsers", it).add(memberUser) + } + } + + /** Identifies the user who created the group */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) /** - * Ids of the groups this group inherits from + * Sets [Builder.userId] to an arbitrary JSON value. * - * An inheriting group has all the users contained in its member groups, as well as all of - * their inherited users + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("member_groups") - @ExcludeMissing - fun memberGroups(memberGroups: JsonField>) = apply { - this.memberGroups = memberGroups - } + fun userId(userId: JsonField) = apply { this.userId = userId } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Group]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .orgId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Group = Group( - id, - orgId, - userId, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("orgId", orgId), created, - name, - description, deletedAt, - memberUsers.map { it.toUnmodifiable() }, - memberGroups.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + description, + (memberGroups ?: JsonMissing.of()).map { it.toImmutable() }, + (memberUsers ?: JsonMissing.of()).map { it.toImmutable() }, + userId, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): Group = apply { + if (validated) { + return@apply + } + + id() + name() + orgId() + created() + deletedAt() + description() + memberGroups() + memberUsers() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (memberGroups.asKnown()?.size ?: 0) + + (memberUsers.asKnown()?.size ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Group && + id == other.id && + name == other.name && + orgId == other.orgId && + created == other.created && + deletedAt == other.deletedAt && + description == other.description && + memberGroups == other.memberGroups && + memberUsers == other.memberUsers && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + orgId, + created, + deletedAt, + description, + memberGroups, + memberUsers, + userId, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Group{id=$id, name=$name, orgId=$orgId, created=$created, deletedAt=$deletedAt, description=$description, memberGroups=$memberGroups, memberUsers=$memberUsers, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupCreateParams.kt index 2c9c24d1..ef507069 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupCreateParams.kt @@ -3,72 +3,186 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new group. If there is an existing group with the same name as the one specified in the + * request, will return the existing group unmodified + */ class GroupCreateParams -constructor( - private val name: String, - private val description: String?, - private val memberGroups: List?, - private val memberUsers: List?, - private val orgName: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun description(): String? = description - - fun memberGroups(): List? = memberGroups - - fun memberUsers(): List? = memberUsers - - fun orgName(): String? = orgName - - internal fun getBody(): GroupCreateBody { - return GroupCreateBody( - name, - description, - memberGroups, - memberUsers, - orgName, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the group + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Textual description of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Ids of the groups this group inherits from + * + * An inheriting group has all the users contained in its member groups, as well as all of their + * inherited users + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberGroups(): List? = body.memberGroups() + + /** + * Ids of users which belong to this group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberUsers(): List? = body.memberUsers() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * group belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [memberGroups]. + * + * Unlike [memberGroups], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _memberGroups(): JsonField> = body._memberGroups() + + /** + * Returns the raw JSON value of [memberUsers]. + * + * Unlike [memberUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _memberUsers(): JsonField> = body._memberUsers() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + 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 [GroupCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [GroupCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = GroupCreateBody.Builder::class) - @NoAutoDetect - class GroupCreateBody - internal constructor( - private val name: String?, - private val description: String?, - private val memberGroups: List?, - private val memberUsers: List?, - private val orgName: String?, - private val additionalProperties: Map, - ) { + internal fun from(groupCreateParams: GroupCreateParams) = apply { + body = groupCreateParams.body.toBuilder() + additionalHeaders = groupCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = groupCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [description] + * - [memberGroups] + * - [memberUsers] + * - [orgName] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the group */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Textual description of the group */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** * Ids of the groups this group inherits from @@ -76,308 +190,585 @@ constructor( * An inheriting group has all the users contained in its member groups, as well as all of * their inherited users */ - @JsonProperty("member_groups") fun memberGroups(): List? = memberGroups + fun memberGroups(memberGroups: List?) = apply { body.memberGroups(memberGroups) } + + /** + * Sets [Builder.memberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.memberGroups] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberGroups(memberGroups: JsonField>) = apply { + body.memberGroups(memberGroups) + } + + /** + * Adds a single [String] to [memberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberGroup(memberGroup: String) = apply { body.addMemberGroup(memberGroup) } /** Ids of users which belong to this group */ - @JsonProperty("member_users") fun memberUsers(): List? = memberUsers + fun memberUsers(memberUsers: List?) = apply { body.memberUsers(memberUsers) } + + /** + * Sets [Builder.memberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.memberUsers] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberUsers(memberUsers: JsonField>) = apply { + body.memberUsers(memberUsers) + } + + /** + * Adds a single [String] to [memberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberUser(memberUser: String) = apply { body.addMemberUser(memberUser) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the group belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is GroupCreateBody && - this.name == other.name && - this.description == other.description && - this.memberGroups == other.memberGroups && - this.memberUsers == other.memberUsers && - this.orgName == other.orgName && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - description, - memberGroups, - memberUsers, - orgName, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "GroupCreateBody{name=$name, description=$description, memberGroups=$memberGroups, memberUsers=$memberUsers, orgName=$orgName, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var description: String? = null - private var memberGroups: List? = null - private var memberUsers: List? = null - private var orgName: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(groupCreateBody: GroupCreateBody) = apply { - this.name = groupCreateBody.name - this.description = groupCreateBody.description - this.memberGroups = groupCreateBody.memberGroups - this.memberUsers = groupCreateBody.memberUsers - this.orgName = groupCreateBody.orgName - additionalProperties(groupCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the group */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Textual description of the group */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * Ids of the groups this group inherits from - * - * An inheriting group has all the users contained in its member groups, as well as all - * of their inherited users - */ - @JsonProperty("member_groups") - fun memberGroups(memberGroups: List) = apply { - this.memberGroups = memberGroups - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Ids of users which belong to this group */ - @JsonProperty("member_users") - fun memberUsers(memberUsers: List) = apply { this.memberUsers = memberUsers } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the group belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): GroupCreateBody = - GroupCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - description, - memberGroups?.toUnmodifiable(), - memberUsers?.toUnmodifiable(), - orgName, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is GroupCreateParams && - this.name == other.name && - this.description == other.description && - this.memberGroups == other.memberGroups && - this.memberUsers == other.memberUsers && - this.orgName == other.orgName && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - name, - description, - memberGroups, - memberUsers, - orgName, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "GroupCreateParams{name=$name, description=$description, memberGroups=$memberGroups, memberUsers=$memberUsers, orgName=$orgName, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [GroupCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GroupCreateParams = + GroupCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var description: String? = null - private var memberGroups: MutableList = mutableListOf() - private var memberUsers: MutableList = mutableListOf() - private var orgName: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(groupCreateParams: GroupCreateParams) = apply { - this.name = groupCreateParams.name - this.description = groupCreateParams.description - this.memberGroups(groupCreateParams.memberGroups ?: listOf()) - this.memberUsers(groupCreateParams.memberUsers ?: listOf()) - this.orgName = groupCreateParams.orgName - additionalQueryParams(groupCreateParams.additionalQueryParams) - additionalHeaders(groupCreateParams.additionalHeaders) - additionalBodyProperties(groupCreateParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the group */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val description: JsonField, + private val memberGroups: JsonField>, + private val memberUsers: JsonField>, + private val orgName: JsonField, + private val additionalProperties: MutableMap, + ) { - /** Textual description of the group */ - fun description(description: String) = apply { this.description = description } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("member_groups") + @ExcludeMissing + memberGroups: JsonField> = JsonMissing.of(), + @JsonProperty("member_users") + @ExcludeMissing + memberUsers: JsonField> = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + ) : this(name, description, memberGroups, memberUsers, orgName, mutableMapOf()) /** - * Ids of the groups this group inherits from + * Name of the group * - * An inheriting group has all the users contained in its member groups, as well as all of - * their inherited users + * @throws BraintrustInvalidDataException 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 memberGroups(memberGroups: List) = apply { - this.memberGroups.clear() - this.memberGroups.addAll(memberGroups) - } + fun name(): String = name.getRequired("name") + + /** + * Textual description of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") /** * Ids of the groups this group inherits from * * An inheriting group has all the users contained in its member groups, as well as all of * their inherited users + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun addMemberGroup(memberGroup: String) = apply { this.memberGroups.add(memberGroup) } - - /** Ids of users which belong to this group */ - fun memberUsers(memberUsers: List) = apply { - this.memberUsers.clear() - this.memberUsers.addAll(memberUsers) - } + fun memberGroups(): List? = memberGroups.getNullable("member_groups") - /** Ids of users which belong to this group */ - fun addMemberUser(memberUser: String) = apply { this.memberUsers.add(memberUser) } + /** + * Ids of users which belong to this group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun memberUsers(): List? = memberUsers.getNullable("member_users") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the group belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * 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 - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [memberGroups]. + * + * Unlike [memberGroups], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("member_groups") + @ExcludeMissing + fun _memberGroups(): JsonField> = memberGroups - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [memberUsers]. + * + * Unlike [memberUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_users") + @ExcludeMissing + fun _memberUsers(): JsonField> = memberUsers - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) + + companion object { - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var name: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var memberGroups: JsonField>? = null + private var memberUsers: JsonField>? = null + private var orgName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + name = body.name + description = body.description + memberGroups = body.memberGroups.map { it.toMutableList() } + memberUsers = body.memberUsers.map { it.toMutableList() } + orgName = body.orgName + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Name of the group */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Textual description of the group */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** + * Ids of the groups this group inherits from + * + * An inheriting group has all the users contained in its member groups, as well as all + * of their inherited users + */ + fun memberGroups(memberGroups: List?) = + memberGroups(JsonField.ofNullable(memberGroups)) + + /** + * Sets [Builder.memberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.memberGroups] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberGroups(memberGroups: JsonField>) = apply { + this.memberGroups = memberGroups.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [memberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberGroup(memberGroup: String) = apply { + memberGroups = + (memberGroups ?: JsonField.of(mutableListOf())).also { + checkKnown("memberGroups", it).add(memberGroup) + } + } + + /** Ids of users which belong to this group */ + fun memberUsers(memberUsers: List?) = + memberUsers(JsonField.ofNullable(memberUsers)) + + /** + * Sets [Builder.memberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.memberUsers] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberUsers(memberUsers: JsonField>) = apply { + this.memberUsers = memberUsers.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [memberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberUser(memberUser: String) = apply { + memberUsers = + (memberUsers ?: JsonField.of(mutableListOf())).also { + checkKnown("memberUsers", it).add(memberUser) + } + } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the group belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + description, + (memberGroups ?: JsonMissing.of()).map { it.toImmutable() }, + (memberUsers ?: JsonMissing.of()).map { it.toImmutable() }, + orgName, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + description() + memberGroups() + memberUsers() + orgName() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): GroupCreateParams = - GroupCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (memberGroups.asKnown()?.size ?: 0) + + (memberUsers.asKnown()?.size ?: 0) + + (if (orgName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + description == other.description && + memberGroups == other.memberGroups && + memberUsers == other.memberUsers && + orgName == other.orgName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + name, description, - if (memberGroups.size == 0) null else memberGroups.toUnmodifiable(), - if (memberUsers.size == 0) null else memberUsers.toUnmodifiable(), + memberGroups, + memberUsers, orgName, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, description=$description, memberGroups=$memberGroups, memberUsers=$memberUsers, orgName=$orgName, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GroupCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "GroupCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupDeleteParams.kt index dcb3e53d..50ec43da 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a group object by its id */ class GroupDeleteParams -constructor( - private val groupId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val groupId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun groupId(): String = groupId + /** Group id */ + fun groupId(): String? = groupId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> groupId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): GroupDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [GroupDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [GroupDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var groupId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(groupDeleteParams: GroupDeleteParams) = apply { + groupId = groupDeleteParams.groupId + additionalHeaders = groupDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = groupDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = groupDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Group id */ + fun groupId(groupId: String?) = apply { this.groupId = groupId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is GroupDeleteParams && - this.groupId == other.groupId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - groupId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "GroupDeleteParams{groupId=$groupId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var groupId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(groupDeleteParams: GroupDeleteParams) = apply { - this.groupId = groupDeleteParams.groupId - additionalQueryParams(groupDeleteParams.additionalQueryParams) - additionalHeaders(groupDeleteParams.additionalHeaders) - additionalBodyProperties(groupDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Group id */ - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [GroupDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): GroupDeleteParams = GroupDeleteParams( - checkNotNull(groupId) { "`groupId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + groupId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> groupId ?: "" + 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 GroupDeleteParams && + groupId == other.groupId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(groupId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "GroupDeleteParams{groupId=$groupId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPage.kt index 80eb4463..39bee40f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPage.kt @@ -2,172 +2,120 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.GroupService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see GroupService.list */ class GroupListPage private constructor( - private val groupsService: GroupService, + private val service: GroupService, private val params: GroupListParams, - private val response: Response, -) { + private val response: GroupListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [GroupListPageResponse], but gracefully handles missing data. + * + * @see GroupListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GroupListPage && - this.groupsService == other.groupsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - groupsService, - params, - response, - ) - } - - override fun toString() = - "GroupListPage{groupsService=$groupsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPageParams(): GroupListParams? { - if (!hasNextPage()) { - return null - } - - return if (params.endingBefore() != null) { - GroupListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): GroupListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - GroupListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): GroupListPage? { - return getNextPageParams()?.let { groupsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(groupsService: GroupService, params: GroupListParams, response: Response) = - GroupListPage( - groupsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): GroupListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): GroupListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): GroupListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [GroupListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [GroupListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: GroupService? = null + private var params: GroupListParams? = null + private var response: GroupListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(groupListPage: GroupListPage) = apply { + service = groupListPage.service + params = groupListPage.params + response = groupListPage.response } - override fun toString() = - "GroupListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: GroupService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: GroupListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: GroupListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [GroupListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GroupListPage = + GroupListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is GroupListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: GroupListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = "GroupListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPageAsync.kt index 8ca5751c..bf60553d 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPageAsync.kt @@ -2,174 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.GroupServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see GroupServiceAsync.list */ class GroupListPageAsync private constructor( - private val groupsService: GroupServiceAsync, + private val service: GroupServiceAsync, private val params: GroupListParams, - private val response: Response, -) { + private val response: GroupListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [GroupListPageResponse], but gracefully handles missing data. + * + * @see GroupListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GroupListPageAsync && - this.groupsService == other.groupsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - groupsService, - params, - response, - ) - } - - override fun toString() = - "GroupListPageAsync{groupsService=$groupsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): GroupListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - GroupListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): GroupListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - GroupListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): GroupListPageAsync? { - return getNextPageParams()?.let { groupsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(groupsService: GroupServiceAsync, params: GroupListParams, response: Response) = - GroupListPageAsync( - groupsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): GroupListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): GroupListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): GroupListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [GroupListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [GroupListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: GroupServiceAsync? = null + private var params: GroupListParams? = null + private var response: GroupListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(groupListPageAsync: GroupListPageAsync) = apply { + service = groupListPageAsync.service + params = groupListPageAsync.params + response = groupListPageAsync.response } - override fun toString() = - "GroupListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: GroupServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: GroupListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: GroupListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [GroupListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GroupListPageAsync = + GroupListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is GroupListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: GroupListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "GroupListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPageResponse.kt new file mode 100644 index 00000000..6cfa3b76 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListPageResponse.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 GroupListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of group objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [GroupListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [GroupListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(groupListPageResponse: GroupListPageResponse) = apply { + objects = groupListPageResponse.objects.map { it.toMutableList() } + additionalProperties = groupListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of group objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Group] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Group) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [GroupListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GroupListPageResponse = + GroupListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GroupListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GroupListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GroupListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListParams.kt index fd5d6cb3..306c04f1 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupListParams.kt @@ -2,106 +2,80 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all groups. The groups are sorted by creation date, with the most recently-created + * groups coming first + */ class GroupListParams -constructor( +private constructor( private val endingBefore: String?, private val groupName: String?, private val ids: Ids?, private val limit: Long?, private val orgName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** Name of the group to search for */ fun groupName(): String? = groupName + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.groupName?.let { params.put("group_name", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GroupListParams && - this.endingBefore == other.endingBefore && - this.groupName == other.groupName && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - groupName, - ids, - limit, - orgName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "GroupListParams{endingBefore=$endingBefore, groupName=$groupName, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): GroupListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [GroupListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [GroupListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var groupName: String? = null @@ -109,18 +83,18 @@ constructor( private var limit: Long? = null private var orgName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(groupListParams: GroupListParams) = apply { - this.endingBefore = groupListParams.endingBefore - this.groupName = groupListParams.groupName - this.ids = groupListParams.ids - this.limit = groupListParams.limit - this.orgName = groupListParams.orgName - this.startingAfter = groupListParams.startingAfter - additionalQueryParams(groupListParams.additionalQueryParams) - additionalHeaders(groupListParams.additionalHeaders) + endingBefore = groupListParams.endingBefore + groupName = groupListParams.groupName + ids = groupListParams.ids + limit = groupListParams.limit + orgName = groupListParams.orgName + startingAfter = groupListParams.startingAfter + additionalHeaders = groupListParams.additionalHeaders.toBuilder() + additionalQueryParams = groupListParams.additionalQueryParams.toBuilder() } /** @@ -130,34 +104,35 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** Name of the group to search for */ - fun groupName(groupName: String) = apply { this.groupName = groupName } + fun groupName(groupName: String?) = apply { this.groupName = groupName } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** * Pagination cursor id. @@ -166,48 +141,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [GroupListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): GroupListParams = GroupListParams( endingBefore, @@ -216,22 +254,46 @@ constructor( limit, orgName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + groupName?.let { put("group_name", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -244,93 +306,74 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) + else -> throw IllegalStateException("Invalid Ids") } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true - } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is GroupListParams && + endingBefore == other.endingBefore && + groupName == other.groupName && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + groupName, + ids, + limit, + orgName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "GroupListParams{endingBefore=$endingBefore, groupName=$groupName, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupReplaceParams.kt index 36d0db55..2ba71a3c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupReplaceParams.kt @@ -3,72 +3,186 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create or replace group. If there is an existing group with the same name as the one specified in + * the request, will replace the existing group with the provided fields + */ class GroupReplaceParams -constructor( - private val name: String, - private val description: String?, - private val memberGroups: List?, - private val memberUsers: List?, - private val orgName: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun description(): String? = description - - fun memberGroups(): List? = memberGroups - - fun memberUsers(): List? = memberUsers - - fun orgName(): String? = orgName - - internal fun getBody(): GroupReplaceBody { - return GroupReplaceBody( - name, - description, - memberGroups, - memberUsers, - orgName, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the group + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Textual description of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Ids of the groups this group inherits from + * + * An inheriting group has all the users contained in its member groups, as well as all of their + * inherited users + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberGroups(): List? = body.memberGroups() + + /** + * Ids of users which belong to this group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberUsers(): List? = body.memberUsers() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * group belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [memberGroups]. + * + * Unlike [memberGroups], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _memberGroups(): JsonField> = body._memberGroups() + + /** + * Returns the raw JSON value of [memberUsers]. + * + * Unlike [memberUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _memberUsers(): JsonField> = body._memberUsers() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + 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 [GroupReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [GroupReplaceParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = GroupReplaceBody.Builder::class) - @NoAutoDetect - class GroupReplaceBody - internal constructor( - private val name: String?, - private val description: String?, - private val memberGroups: List?, - private val memberUsers: List?, - private val orgName: String?, - private val additionalProperties: Map, - ) { + internal fun from(groupReplaceParams: GroupReplaceParams) = apply { + body = groupReplaceParams.body.toBuilder() + additionalHeaders = groupReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = groupReplaceParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [description] + * - [memberGroups] + * - [memberUsers] + * - [orgName] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the group */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Textual description of the group */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** * Ids of the groups this group inherits from @@ -76,308 +190,585 @@ constructor( * An inheriting group has all the users contained in its member groups, as well as all of * their inherited users */ - @JsonProperty("member_groups") fun memberGroups(): List? = memberGroups + fun memberGroups(memberGroups: List?) = apply { body.memberGroups(memberGroups) } + + /** + * Sets [Builder.memberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.memberGroups] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberGroups(memberGroups: JsonField>) = apply { + body.memberGroups(memberGroups) + } + + /** + * Adds a single [String] to [memberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberGroup(memberGroup: String) = apply { body.addMemberGroup(memberGroup) } /** Ids of users which belong to this group */ - @JsonProperty("member_users") fun memberUsers(): List? = memberUsers + fun memberUsers(memberUsers: List?) = apply { body.memberUsers(memberUsers) } + + /** + * Sets [Builder.memberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.memberUsers] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberUsers(memberUsers: JsonField>) = apply { + body.memberUsers(memberUsers) + } + + /** + * Adds a single [String] to [memberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberUser(memberUser: String) = apply { body.addMemberUser(memberUser) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the group belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is GroupReplaceBody && - this.name == other.name && - this.description == other.description && - this.memberGroups == other.memberGroups && - this.memberUsers == other.memberUsers && - this.orgName == other.orgName && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - description, - memberGroups, - memberUsers, - orgName, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "GroupReplaceBody{name=$name, description=$description, memberGroups=$memberGroups, memberUsers=$memberUsers, orgName=$orgName, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var description: String? = null - private var memberGroups: List? = null - private var memberUsers: List? = null - private var orgName: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(groupReplaceBody: GroupReplaceBody) = apply { - this.name = groupReplaceBody.name - this.description = groupReplaceBody.description - this.memberGroups = groupReplaceBody.memberGroups - this.memberUsers = groupReplaceBody.memberUsers - this.orgName = groupReplaceBody.orgName - additionalProperties(groupReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the group */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Textual description of the group */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * Ids of the groups this group inherits from - * - * An inheriting group has all the users contained in its member groups, as well as all - * of their inherited users - */ - @JsonProperty("member_groups") - fun memberGroups(memberGroups: List) = apply { - this.memberGroups = memberGroups - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Ids of users which belong to this group */ - @JsonProperty("member_users") - fun memberUsers(memberUsers: List) = apply { this.memberUsers = memberUsers } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the group belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): GroupReplaceBody = - GroupReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - description, - memberGroups?.toUnmodifiable(), - memberUsers?.toUnmodifiable(), - orgName, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is GroupReplaceParams && - this.name == other.name && - this.description == other.description && - this.memberGroups == other.memberGroups && - this.memberUsers == other.memberUsers && - this.orgName == other.orgName && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - name, - description, - memberGroups, - memberUsers, - orgName, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "GroupReplaceParams{name=$name, description=$description, memberGroups=$memberGroups, memberUsers=$memberUsers, orgName=$orgName, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [GroupReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GroupReplaceParams = + GroupReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var description: String? = null - private var memberGroups: MutableList = mutableListOf() - private var memberUsers: MutableList = mutableListOf() - private var orgName: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(groupReplaceParams: GroupReplaceParams) = apply { - this.name = groupReplaceParams.name - this.description = groupReplaceParams.description - this.memberGroups(groupReplaceParams.memberGroups ?: listOf()) - this.memberUsers(groupReplaceParams.memberUsers ?: listOf()) - this.orgName = groupReplaceParams.orgName - additionalQueryParams(groupReplaceParams.additionalQueryParams) - additionalHeaders(groupReplaceParams.additionalHeaders) - additionalBodyProperties(groupReplaceParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the group */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val description: JsonField, + private val memberGroups: JsonField>, + private val memberUsers: JsonField>, + private val orgName: JsonField, + private val additionalProperties: MutableMap, + ) { - /** Textual description of the group */ - fun description(description: String) = apply { this.description = description } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("member_groups") + @ExcludeMissing + memberGroups: JsonField> = JsonMissing.of(), + @JsonProperty("member_users") + @ExcludeMissing + memberUsers: JsonField> = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + ) : this(name, description, memberGroups, memberUsers, orgName, mutableMapOf()) /** - * Ids of the groups this group inherits from + * Name of the group * - * An inheriting group has all the users contained in its member groups, as well as all of - * their inherited users + * @throws BraintrustInvalidDataException 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 memberGroups(memberGroups: List) = apply { - this.memberGroups.clear() - this.memberGroups.addAll(memberGroups) - } + fun name(): String = name.getRequired("name") + + /** + * Textual description of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") /** * Ids of the groups this group inherits from * * An inheriting group has all the users contained in its member groups, as well as all of * their inherited users + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun addMemberGroup(memberGroup: String) = apply { this.memberGroups.add(memberGroup) } - - /** Ids of users which belong to this group */ - fun memberUsers(memberUsers: List) = apply { - this.memberUsers.clear() - this.memberUsers.addAll(memberUsers) - } + fun memberGroups(): List? = memberGroups.getNullable("member_groups") - /** Ids of users which belong to this group */ - fun addMemberUser(memberUser: String) = apply { this.memberUsers.add(memberUser) } + /** + * Ids of users which belong to this group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun memberUsers(): List? = memberUsers.getNullable("member_users") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the group belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * 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 - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [memberGroups]. + * + * Unlike [memberGroups], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("member_groups") + @ExcludeMissing + fun _memberGroups(): JsonField> = memberGroups - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [memberUsers]. + * + * Unlike [memberUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_users") + @ExcludeMissing + fun _memberUsers(): JsonField> = memberUsers - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) + + companion object { - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var name: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var memberGroups: JsonField>? = null + private var memberUsers: JsonField>? = null + private var orgName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + name = body.name + description = body.description + memberGroups = body.memberGroups.map { it.toMutableList() } + memberUsers = body.memberUsers.map { it.toMutableList() } + orgName = body.orgName + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Name of the group */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Textual description of the group */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** + * Ids of the groups this group inherits from + * + * An inheriting group has all the users contained in its member groups, as well as all + * of their inherited users + */ + fun memberGroups(memberGroups: List?) = + memberGroups(JsonField.ofNullable(memberGroups)) + + /** + * Sets [Builder.memberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.memberGroups] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberGroups(memberGroups: JsonField>) = apply { + this.memberGroups = memberGroups.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [memberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberGroup(memberGroup: String) = apply { + memberGroups = + (memberGroups ?: JsonField.of(mutableListOf())).also { + checkKnown("memberGroups", it).add(memberGroup) + } + } + + /** Ids of users which belong to this group */ + fun memberUsers(memberUsers: List?) = + memberUsers(JsonField.ofNullable(memberUsers)) + + /** + * Sets [Builder.memberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.memberUsers] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberUsers(memberUsers: JsonField>) = apply { + this.memberUsers = memberUsers.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [memberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberUser(memberUser: String) = apply { + memberUsers = + (memberUsers ?: JsonField.of(mutableListOf())).also { + checkKnown("memberUsers", it).add(memberUser) + } + } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the group belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + description, + (memberGroups ?: JsonMissing.of()).map { it.toImmutable() }, + (memberUsers ?: JsonMissing.of()).map { it.toImmutable() }, + orgName, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + description() + memberGroups() + memberUsers() + orgName() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): GroupReplaceParams = - GroupReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (memberGroups.asKnown()?.size ?: 0) + + (memberUsers.asKnown()?.size ?: 0) + + (if (orgName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + description == other.description && + memberGroups == other.memberGroups && + memberUsers == other.memberUsers && + orgName == other.orgName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + name, description, - if (memberGroups.size == 0) null else memberGroups.toUnmodifiable(), - if (memberUsers.size == 0) null else memberUsers.toUnmodifiable(), + memberGroups, + memberUsers, orgName, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, description=$description, memberGroups=$memberGroups, memberUsers=$memberUsers, orgName=$orgName, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GroupReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "GroupReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupRetrieveParams.kt index fd99d2c5..f050c758 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupRetrieveParams.kt @@ -2,125 +2,184 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a group object by its id */ class GroupRetrieveParams -constructor( - private val groupId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val groupId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun groupId(): String = groupId + /** Group id */ + fun groupId(): String? = groupId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> groupId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): GroupRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [GroupRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [GroupRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var groupId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(groupRetrieveParams: GroupRetrieveParams) = apply { + groupId = groupRetrieveParams.groupId + additionalHeaders = groupRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = groupRetrieveParams.additionalQueryParams.toBuilder() } - return other is GroupRetrieveParams && - this.groupId == other.groupId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Group id */ + fun groupId(groupId: String?) = apply { this.groupId = groupId } - override fun hashCode(): Int { - return Objects.hash( - groupId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "GroupRetrieveParams{groupId=$groupId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var groupId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(groupRetrieveParams: GroupRetrieveParams) = apply { - this.groupId = groupRetrieveParams.groupId - additionalQueryParams(groupRetrieveParams.additionalQueryParams) - additionalHeaders(groupRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Group id */ - fun groupId(groupId: String) = apply { this.groupId = groupId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [GroupRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): GroupRetrieveParams = - GroupRetrieveParams( - checkNotNull(groupId) { "`groupId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) + GroupRetrieveParams(groupId, additionalHeaders.build(), additionalQueryParams.build()) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> groupId ?: "" + 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 GroupRetrieveParams && + groupId == other.groupId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(groupId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "GroupRetrieveParams{groupId=$groupId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupUpdateParams.kt index 17a819ea..660b8f62 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/GroupUpdateParams.kt @@ -3,420 +3,885 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update a group object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class GroupUpdateParams -constructor( - private val groupId: String, - private val addMemberGroups: List?, - private val addMemberUsers: List?, - private val description: String?, - private val name: String?, - private val removeMemberGroups: List?, - private val removeMemberUsers: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val groupId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Group id */ + fun groupId(): String? = groupId + + /** + * A list of group IDs to add to the group's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun addMemberGroups(): List? = body.addMemberGroups() + + /** + * A list of user IDs to add to the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun addMemberUsers(): List? = body.addMemberUsers() + + /** + * Textual description of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Name of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * A list of group IDs to remove from the group's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun removeMemberGroups(): List? = body.removeMemberGroups() + + /** + * A list of user IDs to remove from the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun removeMemberUsers(): List? = body.removeMemberUsers() + + /** + * Returns the raw JSON value of [addMemberGroups]. + * + * Unlike [addMemberGroups], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _addMemberGroups(): JsonField> = body._addMemberGroups() + + /** + * Returns the raw JSON value of [addMemberUsers]. + * + * Unlike [addMemberUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _addMemberUsers(): JsonField> = body._addMemberUsers() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [removeMemberGroups]. + * + * Unlike [removeMemberGroups], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _removeMemberGroups(): JsonField> = body._removeMemberGroups() + + /** + * Returns the raw JSON value of [removeMemberUsers]. + * + * Unlike [removeMemberUsers], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _removeMemberUsers(): JsonField> = body._removeMemberUsers() + + 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 groupId(): String = groupId - - fun addMemberGroups(): List? = addMemberGroups + fun toBuilder() = Builder().from(this) - fun addMemberUsers(): List? = addMemberUsers + companion object { - fun description(): String? = description + fun none(): GroupUpdateParams = builder().build() - fun name(): String? = name + /** Returns a mutable builder for constructing an instance of [GroupUpdateParams]. */ + fun builder() = Builder() + } - fun removeMemberGroups(): List? = removeMemberGroups + /** A builder for [GroupUpdateParams]. */ + class Builder internal constructor() { - fun removeMemberUsers(): List? = removeMemberUsers + private var groupId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - internal fun getBody(): GroupUpdateBody { - return GroupUpdateBody( - addMemberGroups, - addMemberUsers, - description, - name, - removeMemberGroups, - removeMemberUsers, - additionalBodyProperties, - ) - } + internal fun from(groupUpdateParams: GroupUpdateParams) = apply { + groupId = groupUpdateParams.groupId + body = groupUpdateParams.body.toBuilder() + additionalHeaders = groupUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = groupUpdateParams.additionalQueryParams.toBuilder() + } - internal fun getQueryParams(): Map> = additionalQueryParams + /** Group id */ + fun groupId(groupId: String?) = apply { this.groupId = groupId } + + /** + * 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: + * - [addMemberGroups] + * - [addMemberUsers] + * - [description] + * - [name] + * - [removeMemberGroups] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } - internal fun getHeaders(): Map> = additionalHeaders + /** A list of group IDs to add to the group's inheriting-from set */ + fun addMemberGroups(addMemberGroups: List?) = apply { + body.addMemberGroups(addMemberGroups) + } - fun getPathParam(index: Int): String { - return when (index) { - 0 -> groupId - else -> "" + /** + * Sets [Builder.addMemberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberGroups] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun addMemberGroups(addMemberGroups: JsonField>) = apply { + body.addMemberGroups(addMemberGroups) } - } - @JsonDeserialize(builder = GroupUpdateBody.Builder::class) - @NoAutoDetect - class GroupUpdateBody - internal constructor( - private val addMemberGroups: List?, - private val addMemberUsers: List?, - private val description: String?, - private val name: String?, - private val removeMemberGroups: List?, - private val removeMemberUsers: List?, - private val additionalProperties: Map, - ) { + /** + * Adds a single [String] to [addMemberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberGroup(addMemberGroup: String) = apply { + body.addAddMemberGroup(addMemberGroup) + } - private var hashCode: Int = 0 + /** A list of user IDs to add to the group */ + fun addMemberUsers(addMemberUsers: List?) = apply { + body.addMemberUsers(addMemberUsers) + } - /** A list of group IDs to add to the group's inheriting-from set */ - @JsonProperty("add_member_groups") fun addMemberGroups(): List? = addMemberGroups + /** + * Sets [Builder.addMemberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberUsers] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun addMemberUsers(addMemberUsers: JsonField>) = apply { + body.addMemberUsers(addMemberUsers) + } - /** A list of user IDs to add to the group */ - @JsonProperty("add_member_users") fun addMemberUsers(): List? = addMemberUsers + /** + * Adds a single [String] to [addMemberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberUser(addMemberUser: String) = apply { body.addAddMemberUser(addMemberUser) } /** Textual description of the group */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** Name of the group */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** A list of group IDs to remove from the group's inheriting-from set */ - @JsonProperty("remove_member_groups") - fun removeMemberGroups(): List? = removeMemberGroups + fun removeMemberGroups(removeMemberGroups: List?) = apply { + body.removeMemberGroups(removeMemberGroups) + } + + /** + * Sets [Builder.removeMemberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberGroups] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun removeMemberGroups(removeMemberGroups: JsonField>) = apply { + body.removeMemberGroups(removeMemberGroups) + } + + /** + * Adds a single [String] to [removeMemberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberGroup(removeMemberGroup: String) = apply { + body.addRemoveMemberGroup(removeMemberGroup) + } /** A list of user IDs to remove from the group */ - @JsonProperty("remove_member_users") - fun removeMemberUsers(): List? = removeMemberUsers + fun removeMemberUsers(removeMemberUsers: List?) = apply { + body.removeMemberUsers(removeMemberUsers) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.removeMemberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberUsers] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun removeMemberUsers(removeMemberUsers: JsonField>) = apply { + body.removeMemberUsers(removeMemberUsers) + } - fun toBuilder() = Builder().from(this) + /** + * Adds a single [String] to [removeMemberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberUser(removeMemberUser: String) = apply { + body.addRemoveMemberUser(removeMemberUser) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - return other is GroupUpdateBody && - this.addMemberGroups == other.addMemberGroups && - this.addMemberUsers == other.addMemberUsers && - this.description == other.description && - this.name == other.name && - this.removeMemberGroups == other.removeMemberGroups && - this.removeMemberUsers == other.removeMemberUsers && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - addMemberGroups, - addMemberUsers, - description, - name, - removeMemberGroups, - removeMemberUsers, - additionalProperties, - ) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "GroupUpdateBody{addMemberGroups=$addMemberGroups, addMemberUsers=$addMemberUsers, description=$description, name=$name, removeMemberGroups=$removeMemberGroups, removeMemberUsers=$removeMemberUsers, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var addMemberGroups: List? = null - private var addMemberUsers: List? = null - private var description: String? = null - private var name: String? = null - private var removeMemberGroups: List? = null - private var removeMemberUsers: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(groupUpdateBody: GroupUpdateBody) = apply { - this.addMemberGroups = groupUpdateBody.addMemberGroups - this.addMemberUsers = groupUpdateBody.addMemberUsers - this.description = groupUpdateBody.description - this.name = groupUpdateBody.name - this.removeMemberGroups = groupUpdateBody.removeMemberGroups - this.removeMemberUsers = groupUpdateBody.removeMemberUsers - additionalProperties(groupUpdateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** A list of group IDs to add to the group's inheriting-from set */ - @JsonProperty("add_member_groups") - fun addMemberGroups(addMemberGroups: List) = apply { - this.addMemberGroups = addMemberGroups - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** A list of user IDs to add to the group */ - @JsonProperty("add_member_users") - fun addMemberUsers(addMemberUsers: List) = apply { - this.addMemberUsers = addMemberUsers - } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Textual description of the group */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Name of the group */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** A list of group IDs to remove from the group's inheriting-from set */ - @JsonProperty("remove_member_groups") - fun removeMemberGroups(removeMemberGroups: List) = apply { - this.removeMemberGroups = removeMemberGroups - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** A list of user IDs to remove from the group */ - @JsonProperty("remove_member_users") - fun removeMemberUsers(removeMemberUsers: List) = apply { - this.removeMemberUsers = removeMemberUsers - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): GroupUpdateBody = - GroupUpdateBody( - addMemberGroups?.toUnmodifiable(), - addMemberUsers?.toUnmodifiable(), - description, - name, - removeMemberGroups?.toUnmodifiable(), - removeMemberUsers?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is GroupUpdateParams && - this.groupId == other.groupId && - this.addMemberGroups == other.addMemberGroups && - this.addMemberUsers == other.addMemberUsers && - this.description == other.description && - this.name == other.name && - this.removeMemberGroups == other.removeMemberGroups && - this.removeMemberUsers == other.removeMemberUsers && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [GroupUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GroupUpdateParams = + GroupUpdateParams( + groupId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - groupId, + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> groupId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val addMemberGroups: JsonField>, + private val addMemberUsers: JsonField>, + private val description: JsonField, + private val name: JsonField, + private val removeMemberGroups: JsonField>, + private val removeMemberUsers: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("add_member_groups") + @ExcludeMissing + addMemberGroups: JsonField> = JsonMissing.of(), + @JsonProperty("add_member_users") + @ExcludeMissing + addMemberUsers: JsonField> = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("remove_member_groups") + @ExcludeMissing + removeMemberGroups: JsonField> = JsonMissing.of(), + @JsonProperty("remove_member_users") + @ExcludeMissing + removeMemberUsers: JsonField> = JsonMissing.of(), + ) : this( addMemberGroups, addMemberUsers, description, name, removeMemberGroups, removeMemberUsers, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - - override fun toString() = - "GroupUpdateParams{groupId=$groupId, addMemberGroups=$addMemberGroups, addMemberUsers=$addMemberUsers, description=$description, name=$name, removeMemberGroups=$removeMemberGroups, removeMemberUsers=$removeMemberUsers, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - fun toBuilder() = Builder().from(this) + /** + * A list of group IDs to add to the group's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun addMemberGroups(): List? = addMemberGroups.getNullable("add_member_groups") + + /** + * A list of user IDs to add to the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun addMemberUsers(): List? = addMemberUsers.getNullable("add_member_users") + + /** + * Textual description of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Name of the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * A list of group IDs to remove from the group's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun removeMemberGroups(): List? = + removeMemberGroups.getNullable("remove_member_groups") + + /** + * A list of user IDs to remove from the group + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun removeMemberUsers(): List? = + removeMemberUsers.getNullable("remove_member_users") + + /** + * Returns the raw JSON value of [addMemberGroups]. + * + * Unlike [addMemberGroups], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("add_member_groups") + @ExcludeMissing + fun _addMemberGroups(): JsonField> = addMemberGroups + + /** + * Returns the raw JSON value of [addMemberUsers]. + * + * Unlike [addMemberUsers], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("add_member_users") + @ExcludeMissing + fun _addMemberUsers(): JsonField> = addMemberUsers + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [removeMemberGroups]. + * + * Unlike [removeMemberGroups], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("remove_member_groups") + @ExcludeMissing + fun _removeMemberGroups(): JsonField> = removeMemberGroups + + /** + * Returns the raw JSON value of [removeMemberUsers]. + * + * Unlike [removeMemberUsers], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("remove_member_users") + @ExcludeMissing + fun _removeMemberUsers(): JsonField> = removeMemberUsers - companion object { + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - fun builder() = Builder() - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - @NoAutoDetect - class Builder { + fun toBuilder() = Builder().from(this) - private var groupId: String? = null - private var addMemberGroups: MutableList = mutableListOf() - private var addMemberUsers: MutableList = mutableListOf() - private var description: String? = null - private var name: String? = null - private var removeMemberGroups: MutableList = mutableListOf() - private var removeMemberUsers: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + companion object { - internal fun from(groupUpdateParams: GroupUpdateParams) = apply { - this.groupId = groupUpdateParams.groupId - this.addMemberGroups(groupUpdateParams.addMemberGroups ?: listOf()) - this.addMemberUsers(groupUpdateParams.addMemberUsers ?: listOf()) - this.description = groupUpdateParams.description - this.name = groupUpdateParams.name - this.removeMemberGroups(groupUpdateParams.removeMemberGroups ?: listOf()) - this.removeMemberUsers(groupUpdateParams.removeMemberUsers ?: listOf()) - additionalQueryParams(groupUpdateParams.additionalQueryParams) - additionalHeaders(groupUpdateParams.additionalHeaders) - additionalBodyProperties(groupUpdateParams.additionalBodyProperties) + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - /** Group id */ - fun groupId(groupId: String) = apply { this.groupId = groupId } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** A list of group IDs to add to the group's inheriting-from set */ - fun addMemberGroups(addMemberGroups: List) = apply { - this.addMemberGroups.clear() - this.addMemberGroups.addAll(addMemberGroups) - } + private var addMemberGroups: JsonField>? = null + private var addMemberUsers: JsonField>? = null + private var description: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var removeMemberGroups: JsonField>? = null + private var removeMemberUsers: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - /** A list of group IDs to add to the group's inheriting-from set */ - fun addAddMemberGroup(addMemberGroup: String) = apply { - this.addMemberGroups.add(addMemberGroup) - } + internal fun from(body: Body) = apply { + addMemberGroups = body.addMemberGroups.map { it.toMutableList() } + addMemberUsers = body.addMemberUsers.map { it.toMutableList() } + description = body.description + name = body.name + removeMemberGroups = body.removeMemberGroups.map { it.toMutableList() } + removeMemberUsers = body.removeMemberUsers.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - /** A list of user IDs to add to the group */ - fun addMemberUsers(addMemberUsers: List) = apply { - this.addMemberUsers.clear() - this.addMemberUsers.addAll(addMemberUsers) - } + /** A list of group IDs to add to the group's inheriting-from set */ + fun addMemberGroups(addMemberGroups: List?) = + addMemberGroups(JsonField.ofNullable(addMemberGroups)) + + /** + * Sets [Builder.addMemberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberGroups] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun addMemberGroups(addMemberGroups: JsonField>) = apply { + this.addMemberGroups = addMemberGroups.map { it.toMutableList() } + } - /** A list of user IDs to add to the group */ - fun addAddMemberUser(addMemberUser: String) = apply { - this.addMemberUsers.add(addMemberUser) - } + /** + * Adds a single [String] to [addMemberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberGroup(addMemberGroup: String) = apply { + addMemberGroups = + (addMemberGroups ?: JsonField.of(mutableListOf())).also { + checkKnown("addMemberGroups", it).add(addMemberGroup) + } + } - /** Textual description of the group */ - fun description(description: String) = apply { this.description = description } + /** A list of user IDs to add to the group */ + fun addMemberUsers(addMemberUsers: List?) = + addMemberUsers(JsonField.ofNullable(addMemberUsers)) + + /** + * Sets [Builder.addMemberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberUsers] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun addMemberUsers(addMemberUsers: JsonField>) = apply { + this.addMemberUsers = addMemberUsers.map { it.toMutableList() } + } - /** Name of the group */ - fun name(name: String) = apply { this.name = name } + /** + * Adds a single [String] to [addMemberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberUser(addMemberUser: String) = apply { + addMemberUsers = + (addMemberUsers ?: JsonField.of(mutableListOf())).also { + checkKnown("addMemberUsers", it).add(addMemberUser) + } + } - /** A list of group IDs to remove from the group's inheriting-from set */ - fun removeMemberGroups(removeMemberGroups: List) = apply { - this.removeMemberGroups.clear() - this.removeMemberGroups.addAll(removeMemberGroups) - } + /** Textual description of the group */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - /** A list of group IDs to remove from the group's inheriting-from set */ - fun addRemoveMemberGroup(removeMemberGroup: String) = apply { - this.removeMemberGroups.add(removeMemberGroup) - } + /** Name of the group */ + fun name(name: String?) = name(JsonField.ofNullable(name)) - /** A list of user IDs to remove from the group */ - fun removeMemberUsers(removeMemberUsers: List) = apply { - this.removeMemberUsers.clear() - this.removeMemberUsers.addAll(removeMemberUsers) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** A list of user IDs to remove from the group */ - fun addRemoveMemberUser(removeMemberUser: String) = apply { - this.removeMemberUsers.add(removeMemberUser) - } + /** A list of group IDs to remove from the group's inheriting-from set */ + fun removeMemberGroups(removeMemberGroups: List?) = + removeMemberGroups(JsonField.ofNullable(removeMemberGroups)) + + /** + * Sets [Builder.removeMemberGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberGroups] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun removeMemberGroups(removeMemberGroups: JsonField>) = apply { + this.removeMemberGroups = removeMemberGroups.map { it.toMutableList() } + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Adds a single [String] to [removeMemberGroups]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberGroup(removeMemberGroup: String) = apply { + removeMemberGroups = + (removeMemberGroups ?: JsonField.of(mutableListOf())).also { + checkKnown("removeMemberGroups", it).add(removeMemberGroup) + } + } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** A list of user IDs to remove from the group */ + fun removeMemberUsers(removeMemberUsers: List?) = + removeMemberUsers(JsonField.ofNullable(removeMemberUsers)) + + /** + * Sets [Builder.removeMemberUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberUsers] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun removeMemberUsers(removeMemberUsers: JsonField>) = apply { + this.removeMemberUsers = removeMemberUsers.map { it.toMutableList() } + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Adds a single [String] to [removeMemberUsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberUser(removeMemberUser: String) = apply { + removeMemberUsers = + (removeMemberUsers ?: JsonField.of(mutableListOf())).also { + checkKnown("removeMemberUsers", it).add(removeMemberUser) + } + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body( + (addMemberGroups ?: JsonMissing.of()).map { it.toImmutable() }, + (addMemberUsers ?: JsonMissing.of()).map { it.toImmutable() }, + description, + name, + (removeMemberGroups ?: JsonMissing.of()).map { it.toImmutable() }, + (removeMemberUsers ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + private var validated: Boolean = false - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun validate(): Body = apply { + if (validated) { + return@apply + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + addMemberGroups() + addMemberUsers() + description() + name() + removeMemberGroups() + removeMemberUsers() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): GroupUpdateParams = - GroupUpdateParams( - checkNotNull(groupId) { "`groupId` is required but was not set" }, - if (addMemberGroups.size == 0) null else addMemberGroups.toUnmodifiable(), - if (addMemberUsers.size == 0) null else addMemberUsers.toUnmodifiable(), + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (addMemberGroups.asKnown()?.size ?: 0) + + (addMemberUsers.asKnown()?.size ?: 0) + + (if (description.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (removeMemberGroups.asKnown()?.size ?: 0) + + (removeMemberUsers.asKnown()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + addMemberGroups == other.addMemberGroups && + addMemberUsers == other.addMemberUsers && + description == other.description && + name == other.name && + removeMemberGroups == other.removeMemberGroups && + removeMemberUsers == other.removeMemberUsers && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + addMemberGroups, + addMemberUsers, description, name, - if (removeMemberGroups.size == 0) null else removeMemberGroups.toUnmodifiable(), - if (removeMemberUsers.size == 0) null else removeMemberUsers.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + removeMemberGroups, + removeMemberUsers, + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{addMemberGroups=$addMemberGroups, addMemberUsers=$addMemberUsers, description=$description, name=$name, removeMemberGroups=$removeMemberGroups, removeMemberUsers=$removeMemberUsers, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GroupUpdateParams && + groupId == other.groupId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(groupId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "GroupUpdateParams{groupId=$groupId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEvent.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEvent.kt new file mode 100644 index 00000000..91ec6c71 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEvent.kt @@ -0,0 +1,1013 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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.util.Collections +import java.util.Objects + +/** A dataset event */ +class InsertDatasetEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val _isMerge: JsonField, + private val _mergePaths: JsonField>>, + private val _objectDelete: JsonField, + private val _parentId: JsonField, + private val created: JsonField, + private val expected: JsonValue, + private val input: JsonValue, + private val metadata: JsonField, + private val origin: JsonField, + private val rootSpanId: JsonField, + private val spanId: JsonField, + private val spanParents: JsonField>, + private val tags: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_is_merge") @ExcludeMissing _isMerge: JsonField = JsonMissing.of(), + @JsonProperty("_merge_paths") + @ExcludeMissing + _mergePaths: JsonField>> = JsonMissing.of(), + @JsonProperty("_object_delete") + @ExcludeMissing + _objectDelete: JsonField = JsonMissing.of(), + @JsonProperty("_parent_id") @ExcludeMissing _parentId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonValue = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("origin") + @ExcludeMissing + origin: JsonField = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("span_id") @ExcludeMissing spanId: JsonField = JsonMissing.of(), + @JsonProperty("span_parents") + @ExcludeMissing + spanParents: JsonField> = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _isMerge, + _mergePaths, + _objectDelete, + _parentId, + created, + expected, + input, + metadata, + origin, + rootSpanId, + spanId, + spanParents, + tags, + mutableMapOf(), + ) + + /** + * A unique identifier for the dataset event. If you don't provide one, BrainTrust will generate + * one for you + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun id(): String? = id.getNullable("id") + + /** + * The `_is_merge` field controls how the row is merged with any existing row with the same id + * in the DB. By default (or when set to `false`), the existing row is completely replaced by + * the new row. When set to `true`, the new row is deep-merged into the existing row, if one is + * found. If no existing row is found, the new row is inserted as is. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": + * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": + * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we + * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be + * `{"id": "foo", "input": {"b": 11, "c": 20}}` + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _isMerge(): Boolean? = _isMerge.getNullable("_is_merge") + + /** + * The `_merge_paths` field allows controlling the depth of the merge, when `_is_merge=true`. + * `_merge_paths` is a list of paths, where each path is a list of field names. The deep merge + * will not descend below any of the specified merge paths. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, + * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, + * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, + * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": + * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the + * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and + * `input.c`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _mergePaths(): List>? = _mergePaths.getNullable("_merge_paths") + + /** + * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not show up + * in subsequent fetches for this dataset + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") + + /** + * DEPRECATED: The `_parent_id` field is deprecated and should not be used. Support for + * `_parent_id` will be dropped in a future version of Braintrust. Log `span_id`, + * `root_span_id`, and `span_parents` explicitly instead. + * + * Use the `_parent_id` field to create this row as a subspan of an existing row. Tracking + * hierarchical relationships are important for tracing (see the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). + * + * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", + * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent + * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after + * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row + * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this + * case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _parentId(): String? = _parentId.getNullable("_parent_id") + + /** + * The timestamp the dataset event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") + + /** + * The output of your application, including post-processing (an arbitrary, JSON serializable + * object) + */ + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected + + /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonValue = input + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. For + * example, you could log the `prompt`, example's `id`, or anything else that would be useful to + * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys + * must be strings + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + + /** + * Indicates the event was copied from another object. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun origin(): ObjectReference? = origin.getNullable("origin") + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun rootSpanId(): String? = rootSpanId.getNullable("root_span_id") + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanId(): String? = spanId.getNullable("span_id") + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanParents(): List? = spanParents.getNullable("span_parents") + + /** + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") + + /** + * 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 [_isMerge]. + * + * Unlike [_isMerge], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge(): JsonField = _isMerge + + /** + * Returns the raw JSON value of [_mergePaths]. + * + * Unlike [_mergePaths], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_merge_paths") + @ExcludeMissing + fun __mergePaths(): JsonField>> = _mergePaths + + /** + * Returns the raw JSON value of [_objectDelete]. + * + * Unlike [_objectDelete], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_object_delete") + @ExcludeMissing + fun __objectDelete(): JsonField = _objectDelete + + /** + * Returns the raw JSON value of [_parentId]. + * + * Unlike [_parentId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_parent_id") @ExcludeMissing fun __parentId(): JsonField = _parentId + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * 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 [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin + + /** + * Returns the raw JSON value of [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId(): JsonField = rootSpanId + + /** + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId + + /** + * Returns the raw JSON value of [spanParents]. + * + * Unlike [spanParents], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_parents") + @ExcludeMissing + fun _spanParents(): JsonField> = spanParents + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags + + @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 [InsertDatasetEvent]. */ + fun builder() = Builder() + } + + /** A builder for [InsertDatasetEvent]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var _isMerge: JsonField = JsonMissing.of() + private var _mergePaths: JsonField>>? = null + private var _objectDelete: JsonField = JsonMissing.of() + private var _parentId: JsonField = JsonMissing.of() + private var created: JsonField = JsonMissing.of() + private var expected: JsonValue = JsonMissing.of() + private var input: JsonValue = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var rootSpanId: JsonField = JsonMissing.of() + private var spanId: JsonField = JsonMissing.of() + private var spanParents: JsonField>? = null + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(insertDatasetEvent: InsertDatasetEvent) = apply { + id = insertDatasetEvent.id + _isMerge = insertDatasetEvent._isMerge + _mergePaths = insertDatasetEvent._mergePaths.map { it.toMutableList() } + _objectDelete = insertDatasetEvent._objectDelete + _parentId = insertDatasetEvent._parentId + created = insertDatasetEvent.created + expected = insertDatasetEvent.expected + input = insertDatasetEvent.input + metadata = insertDatasetEvent.metadata + origin = insertDatasetEvent.origin + rootSpanId = insertDatasetEvent.rootSpanId + spanId = insertDatasetEvent.spanId + spanParents = insertDatasetEvent.spanParents.map { it.toMutableList() } + tags = insertDatasetEvent.tags.map { it.toMutableList() } + additionalProperties = insertDatasetEvent.additionalProperties.toMutableMap() + } + + /** + * A unique identifier for the dataset event. If you don't provide one, BrainTrust will + * generate one for you + */ + fun id(id: String?) = id(JsonField.ofNullable(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 } + + /** + * The `_is_merge` field controls how the row is merged with any existing row with the same + * id in the DB. By default (or when set to `false`), the existing row is completely + * replaced by the new row. When set to `true`, the new row is deep-merged into the existing + * row, if one is found. If no existing row is found, the new row is inserted as is. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": + * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": + * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we + * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be + * `{"id": "foo", "input": {"b": 11, "c": 20}}` + */ + fun _isMerge(_isMerge: Boolean?) = _isMerge(JsonField.ofNullable(_isMerge)) + + /** + * Alias for [Builder._isMerge]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun _isMerge(_isMerge: Boolean) = _isMerge(_isMerge as Boolean?) + + /** + * Sets [Builder._isMerge] to an arbitrary JSON value. + * + * You should usually call [Builder._isMerge] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } + + /** + * The `_merge_paths` field allows controlling the depth of the merge, when + * `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of field + * names. The deep merge will not descend below any of the specified merge paths. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": + * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": + * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": + * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": + * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this + * case, due to the merge paths, we have replaced `input.a` and `output`, but have still + * deep-merged `input` and `input.c`. + */ + fun _mergePaths(_mergePaths: List>?) = + _mergePaths(JsonField.ofNullable(_mergePaths)) + + /** + * Sets [Builder._mergePaths] to an arbitrary JSON value. + * + * You should usually call [Builder._mergePaths] with a well-typed `List>` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun _mergePaths(_mergePaths: JsonField>>) = apply { + this._mergePaths = _mergePaths.map { it.toMutableList() } + } + + /** + * Adds a single [List] to [_mergePaths]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMergePath(mergePath: List) = apply { + _mergePaths = + (_mergePaths ?: JsonField.of(mutableListOf())).also { + checkKnown("_mergePaths", it).add(mergePath) + } + } + + /** + * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not + * show up in subsequent fetches for this dataset + */ + fun _objectDelete(_objectDelete: Boolean?) = + _objectDelete(JsonField.ofNullable(_objectDelete)) + + /** + * Alias for [Builder._objectDelete]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun _objectDelete(_objectDelete: Boolean) = _objectDelete(_objectDelete as Boolean?) + + /** + * Sets [Builder._objectDelete] to an arbitrary JSON value. + * + * You should usually call [Builder._objectDelete] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun _objectDelete(_objectDelete: JsonField) = apply { + this._objectDelete = _objectDelete + } + + /** + * DEPRECATED: The `_parent_id` field is deprecated and should not be used. Support for + * `_parent_id` will be dropped in a future version of Braintrust. Log `span_id`, + * `root_span_id`, and `span_parents` explicitly instead. + * + * Use the `_parent_id` field to create this row as a subspan of an existing row. Tracking + * hierarchical relationships are important for tracing (see the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). + * + * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", + * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the + * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the + * root span row `"abc"` will show up in the summary view. You can view the full trace + * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun _parentId(_parentId: String?) = _parentId(JsonField.ofNullable(_parentId)) + + /** + * Sets [Builder._parentId] to an arbitrary JSON value. + * + * You should usually call [Builder._parentId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _parentId(_parentId: JsonField) = apply { this._parentId = _parentId } + + /** The timestamp the dataset event was created */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } + + /** + * The output of your application, including post-processing (an arbitrary, JSON + * serializable object) + */ + fun expected(expected: JsonValue) = apply { this.expected = expected } + + /** + * The argument that uniquely define an input case (an arbitrary, JSON serializable object) + */ + fun input(input: JsonValue) = apply { this.input = input } + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. + * For example, you could log the `prompt`, example's `id`, or anything else that would be + * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, + * but its keys must be strings + */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + + /** Indicates the event was copied from another object. */ + fun origin(origin: ObjectReference?) = origin(JsonField.ofNullable(origin)) + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [ObjectReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun origin(origin: JsonField) = apply { this.origin = origin } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun rootSpanId(rootSpanId: String?) = rootSpanId(JsonField.ofNullable(rootSpanId)) + + /** + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun spanId(spanId: String?) = spanId(JsonField.ofNullable(spanId)) + + /** + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun spanParents(spanParents: List?) = spanParents(JsonField.ofNullable(spanParents)) + + /** + * Sets [Builder.spanParents] to an arbitrary JSON value. + * + * You should usually call [Builder.spanParents] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun spanParents(spanParents: JsonField>) = apply { + this.spanParents = spanParents.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [spanParents]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSpanParent(spanParent: String) = apply { + spanParents = + (spanParents ?: JsonField.of(mutableListOf())).also { + checkKnown("spanParents", it).add(spanParent) + } + } + + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + + 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 [InsertDatasetEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): InsertDatasetEvent = + InsertDatasetEvent( + id, + _isMerge, + (_mergePaths ?: JsonMissing.of()).map { it.toImmutable() }, + _objectDelete, + _parentId, + created, + expected, + input, + metadata, + origin, + rootSpanId, + spanId, + (spanParents ?: JsonMissing.of()).map { it.toImmutable() }, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): InsertDatasetEvent = apply { + if (validated) { + return@apply + } + + id() + _isMerge() + _mergePaths() + _objectDelete() + _parentId() + created() + metadata()?.validate() + origin()?.validate() + rootSpanId() + spanId() + spanParents() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_isMerge.asKnown() == null) 0 else 1) + + (_mergePaths.asKnown()?.sumOf { it.size.toInt() } ?: 0) + + (if (_objectDelete.asKnown() == null) 0 else 1) + + (if (_parentId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (if (spanId.asKnown() == null) 0 else 1) + + (spanParents.asKnown()?.size ?: 0) + + (tags.asKnown()?.size ?: 0) + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. For + * example, you could log the `prompt`, example's `id`, or anything else that would be useful to + * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys + * must be strings + */ + class Metadata + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of() + ) : this(model, mutableMapOf()) + + /** + * The model used for this example + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): String? = model.getNullable("model") + + /** + * 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 + + @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 [Metadata]. */ + fun builder() = Builder() + } + + /** A builder for [Metadata]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(metadata: Metadata) = apply { + model = metadata.model + additionalProperties = metadata.additionalProperties.toMutableMap() + } + + /** The model used for this example */ + fun model(model: String?) = model(JsonField.ofNullable(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 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(model, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + model() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (model.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && + model == other.model && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(model, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metadata{model=$model, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InsertDatasetEvent && + id == other.id && + _isMerge == other._isMerge && + _mergePaths == other._mergePaths && + _objectDelete == other._objectDelete && + _parentId == other._parentId && + created == other.created && + expected == other.expected && + input == other.input && + metadata == other.metadata && + origin == other.origin && + rootSpanId == other.rootSpanId && + spanId == other.spanId && + spanParents == other.spanParents && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + _isMerge, + _mergePaths, + _objectDelete, + _parentId, + created, + expected, + input, + metadata, + origin, + rootSpanId, + spanId, + spanParents, + tags, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InsertDatasetEvent{id=$id, _isMerge=$_isMerge, _mergePaths=$_mergePaths, _objectDelete=$_objectDelete, _parentId=$_parentId, created=$created, expected=$expected, input=$input, metadata=$metadata, origin=$origin, rootSpanId=$rootSpanId, spanId=$spanId, spanParents=$spanParents, tags=$tags, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEventMerge.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEventMerge.kt deleted file mode 100755 index 4990ff65..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEventMerge.kt +++ /dev/null @@ -1,509 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import java.time.OffsetDateTime -import java.util.Objects - -@JsonDeserialize(builder = InsertDatasetEventMerge.Builder::class) -@NoAutoDetect -class InsertDatasetEventMerge -private constructor( - private val input: JsonValue, - private val expected: JsonValue, - private val metadata: JsonField, - private val tags: JsonField>, - private val id: JsonField, - private val created: JsonField, - private val _objectDelete: JsonField, - private val _isMerge: JsonField, - private val _mergePaths: JsonField>>, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ - fun input(): JsonValue = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object) - */ - fun expected(): JsonValue = expected - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - fun metadata(): Metadata? = metadata.getNullable("metadata") - - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will generate - * one for you - */ - fun id(): String? = id.getNullable("id") - - /** The timestamp the dataset event was created */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not show up - * in subsequent fetches for this dataset - */ - fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(): Boolean = _isMerge.getRequired("_is_merge") - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be specified - * alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of - * field names. The deep merge will not descend below any of the specified merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, - * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, - * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, - * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": - * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the - * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and - * `input.c`. - */ - fun _mergePaths(): List>? = _mergePaths.getNullable("_merge_paths") - - /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ - @JsonProperty("input") @ExcludeMissing fun _input() = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object) - */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will generate - * one for you - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** The timestamp the dataset event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not show up - * in subsequent fetches for this dataset - */ - @JsonProperty("_object_delete") @ExcludeMissing fun __objectDelete() = _objectDelete - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge() = _isMerge - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be specified - * alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of - * field names. The deep merge will not descend below any of the specified merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, - * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, - * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, - * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": - * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the - * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and - * `input.c`. - */ - @JsonProperty("_merge_paths") @ExcludeMissing fun __mergePaths() = _mergePaths - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InsertDatasetEventMerge = apply { - if (!validated) { - input() - expected() - metadata()?.validate() - tags() - id() - created() - _objectDelete() - _isMerge() - _mergePaths() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InsertDatasetEventMerge && - this.input == other.input && - this.expected == other.expected && - this.metadata == other.metadata && - this.tags == other.tags && - this.id == other.id && - this.created == other.created && - this._objectDelete == other._objectDelete && - this._isMerge == other._isMerge && - this._mergePaths == other._mergePaths && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - input, - expected, - metadata, - tags, - id, - created, - _objectDelete, - _isMerge, - _mergePaths, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InsertDatasetEventMerge{input=$input, expected=$expected, metadata=$metadata, tags=$tags, id=$id, created=$created, _objectDelete=$_objectDelete, _isMerge=$_isMerge, _mergePaths=$_mergePaths, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var input: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var id: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var _objectDelete: JsonField = JsonMissing.of() - private var _isMerge: JsonField = JsonMissing.of() - private var _mergePaths: JsonField>> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(insertDatasetEventMerge: InsertDatasetEventMerge) = apply { - this.input = insertDatasetEventMerge.input - this.expected = insertDatasetEventMerge.expected - this.metadata = insertDatasetEventMerge.metadata - this.tags = insertDatasetEventMerge.tags - this.id = insertDatasetEventMerge.id - this.created = insertDatasetEventMerge.created - this._objectDelete = insertDatasetEventMerge._objectDelete - this._isMerge = insertDatasetEventMerge._isMerge - this._mergePaths = insertDatasetEventMerge._mergePaths - additionalProperties(insertDatasetEventMerge.additionalProperties) - } - - /** - * The argument that uniquely define an input case (an arbitrary, JSON serializable object) - */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } - - /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object) - */ - @JsonProperty("expected") - @ExcludeMissing - fun expected(expected: JsonValue) = apply { this.expected = expected } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(id: String) = id(JsonField.of(id)) - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** The timestamp the dataset event was created */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** The timestamp the dataset event was created */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not - * show up in subsequent fetches for this dataset - */ - fun _objectDelete(_objectDelete: Boolean) = _objectDelete(JsonField.of(_objectDelete)) - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not - * show up in subsequent fetches for this dataset - */ - @JsonProperty("_object_delete") - @ExcludeMissing - fun _objectDelete(_objectDelete: JsonField) = apply { - this._objectDelete = _objectDelete - } - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(_isMerge: Boolean) = _isMerge(JsonField.of(_isMerge)) - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") - @ExcludeMissing - fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be - * specified alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path - * is a list of field names. The deep merge will not descend below any of the specified - * merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": - * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": - * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": - * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": - * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this - * case, due to the merge paths, we have replaced `input.a` and `output`, but have still - * deep-merged `input` and `input.c`. - */ - fun _mergePaths(_mergePaths: List>) = _mergePaths(JsonField.of(_mergePaths)) - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be - * specified alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path - * is a list of field names. The deep merge will not descend below any of the specified - * merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": - * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": - * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": - * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": - * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this - * case, due to the merge paths, we have replaced `input.a` and `output`, but have still - * deep-merged `input` and `input.c`. - */ - @JsonProperty("_merge_paths") - @ExcludeMissing - fun _mergePaths(_mergePaths: JsonField>>) = apply { - this._mergePaths = _mergePaths - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): InsertDatasetEventMerge = - InsertDatasetEventMerge( - input, - expected, - metadata, - tags.map { it.toUnmodifiable() }, - id, - created, - _objectDelete, - _isMerge, - _mergePaths.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), - ) - } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEventReplace.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEventReplace.kt deleted file mode 100755 index 6e21cffe..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertDatasetEventReplace.kt +++ /dev/null @@ -1,503 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import java.time.OffsetDateTime -import java.util.Objects - -@JsonDeserialize(builder = InsertDatasetEventReplace.Builder::class) -@NoAutoDetect -class InsertDatasetEventReplace -private constructor( - private val input: JsonValue, - private val expected: JsonValue, - private val metadata: JsonField, - private val tags: JsonField>, - private val id: JsonField, - private val created: JsonField, - private val _objectDelete: JsonField, - private val _isMerge: JsonField, - private val _parentId: JsonField, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ - fun input(): JsonValue = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object) - */ - fun expected(): JsonValue = expected - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - fun metadata(): Metadata? = metadata.getNullable("metadata") - - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will generate - * one for you - */ - fun id(): String? = id.getNullable("id") - - /** The timestamp the dataset event was created */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not show up - * in subsequent fetches for this dataset - */ - fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(): Boolean? = _isMerge.getNullable("_is_merge") - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot be - * specified alongside `_is_merge=true`. Tracking hierarchical relationships are important for - * tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent - * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after - * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row - * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this - * case, the `"llm_call"` row) by clicking on the "abc" row. - */ - fun _parentId(): String? = _parentId.getNullable("_parent_id") - - /** The argument that uniquely define an input case (an arbitrary, JSON serializable object) */ - @JsonProperty("input") @ExcludeMissing fun _input() = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object) - */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will generate - * one for you - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** The timestamp the dataset event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not show up - * in subsequent fetches for this dataset - */ - @JsonProperty("_object_delete") @ExcludeMissing fun __objectDelete() = _objectDelete - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge() = _isMerge - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot be - * specified alongside `_is_merge=true`. Tracking hierarchical relationships are important for - * tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent - * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after - * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row - * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this - * case, the `"llm_call"` row) by clicking on the "abc" row. - */ - @JsonProperty("_parent_id") @ExcludeMissing fun __parentId() = _parentId - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InsertDatasetEventReplace = apply { - if (!validated) { - input() - expected() - metadata()?.validate() - tags() - id() - created() - _objectDelete() - _isMerge() - _parentId() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InsertDatasetEventReplace && - this.input == other.input && - this.expected == other.expected && - this.metadata == other.metadata && - this.tags == other.tags && - this.id == other.id && - this.created == other.created && - this._objectDelete == other._objectDelete && - this._isMerge == other._isMerge && - this._parentId == other._parentId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - input, - expected, - metadata, - tags, - id, - created, - _objectDelete, - _isMerge, - _parentId, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InsertDatasetEventReplace{input=$input, expected=$expected, metadata=$metadata, tags=$tags, id=$id, created=$created, _objectDelete=$_objectDelete, _isMerge=$_isMerge, _parentId=$_parentId, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var input: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var id: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var _objectDelete: JsonField = JsonMissing.of() - private var _isMerge: JsonField = JsonMissing.of() - private var _parentId: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(insertDatasetEventReplace: InsertDatasetEventReplace) = apply { - this.input = insertDatasetEventReplace.input - this.expected = insertDatasetEventReplace.expected - this.metadata = insertDatasetEventReplace.metadata - this.tags = insertDatasetEventReplace.tags - this.id = insertDatasetEventReplace.id - this.created = insertDatasetEventReplace.created - this._objectDelete = insertDatasetEventReplace._objectDelete - this._isMerge = insertDatasetEventReplace._isMerge - this._parentId = insertDatasetEventReplace._parentId - additionalProperties(insertDatasetEventReplace.additionalProperties) - } - - /** - * The argument that uniquely define an input case (an arbitrary, JSON serializable object) - */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } - - /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object) - */ - @JsonProperty("expected") - @ExcludeMissing - fun expected(expected: JsonValue) = apply { this.expected = expected } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(id: String) = id(JsonField.of(id)) - - /** - * A unique identifier for the dataset event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** The timestamp the dataset event was created */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** The timestamp the dataset event was created */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not - * show up in subsequent fetches for this dataset - */ - fun _objectDelete(_objectDelete: Boolean) = _objectDelete(JsonField.of(_objectDelete)) - - /** - * Pass `_object_delete=true` to mark the dataset event deleted. Deleted events will not - * show up in subsequent fetches for this dataset - */ - @JsonProperty("_object_delete") - @ExcludeMissing - fun _objectDelete(_objectDelete: JsonField) = apply { - this._objectDelete = _objectDelete - } - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(_isMerge: Boolean) = _isMerge(JsonField.of(_isMerge)) - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") - @ExcludeMissing - fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot - * be specified alongside `_is_merge=true`. Tracking hierarchical relationships are - * important for tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) - * for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the - * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What - * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the - * root span row `"abc"` will show up in the summary view. You can view the full trace - * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. - */ - fun _parentId(_parentId: String) = _parentId(JsonField.of(_parentId)) - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot - * be specified alongside `_is_merge=true`. Tracking hierarchical relationships are - * important for tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) - * for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the - * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What - * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the - * root span row `"abc"` will show up in the summary view. You can view the full trace - * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. - */ - @JsonProperty("_parent_id") - @ExcludeMissing - fun _parentId(_parentId: JsonField) = apply { this._parentId = _parentId } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): InsertDatasetEventReplace = - InsertDatasetEventReplace( - input, - expected, - metadata, - tags.map { it.toUnmodifiable() }, - id, - created, - _objectDelete, - _isMerge, - _parentId, - additionalProperties.toUnmodifiable(), - ) - } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertEventsResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertEventsResponse.kt index 62ed4675..83886167 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertEventsResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertEventsResponse.kt @@ -6,82 +6,78 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = InsertEventsResponse.Builder::class) -@NoAutoDetect class InsertEventsResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val rowIds: JsonField>, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("row_ids") @ExcludeMissing rowIds: JsonField> = JsonMissing.of() + ) : this(rowIds, mutableMapOf()) /** * The ids of all rows that were inserted, aligning one-to-one with the rows provided as input + * + * @throws BraintrustInvalidDataException 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 rowIds(): List = rowIds.getRequired("row_ids") /** - * The ids of all rows that were inserted, aligning one-to-one with the rows provided as input + * Returns the raw JSON value of [rowIds]. + * + * Unlike [rowIds], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("row_ids") @ExcludeMissing fun _rowIds() = rowIds + @JsonProperty("row_ids") @ExcludeMissing fun _rowIds(): JsonField> = rowIds + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InsertEventsResponse = apply { - if (!validated) { - rowIds() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InsertEventsResponse && - this.rowIds == other.rowIds && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(rowIds, additionalProperties) - } - return hashCode - } - - override fun toString() = - "InsertEventsResponse{rowIds=$rowIds, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [InsertEventsResponse]. + * + * The following fields are required: + * ```kotlin + * .rowIds() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [InsertEventsResponse]. */ + class Builder internal constructor() { - private var rowIds: JsonField> = JsonMissing.of() + private var rowIds: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(insertEventsResponse: InsertEventsResponse) = apply { - this.rowIds = insertEventsResponse.rowIds - additionalProperties(insertEventsResponse.additionalProperties) + rowIds = insertEventsResponse.rowIds.map { it.toMutableList() } + additionalProperties = insertEventsResponse.additionalProperties.toMutableMap() } /** @@ -91,31 +87,106 @@ private constructor( fun rowIds(rowIds: List) = rowIds(JsonField.of(rowIds)) /** - * The ids of all rows that were inserted, aligning one-to-one with the rows provided as - * input + * Sets [Builder.rowIds] to an arbitrary JSON value. + * + * You should usually call [Builder.rowIds] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun rowIds(rowIds: JsonField>) = apply { + this.rowIds = rowIds.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [rowIds]. + * + * @throws IllegalStateException if the field was previously set to a non-list. */ - @JsonProperty("row_ids") - @ExcludeMissing - fun rowIds(rowIds: JsonField>) = apply { this.rowIds = rowIds } + fun addRowId(rowId: String) = apply { + rowIds = + (rowIds ?: JsonField.of(mutableListOf())).also { + checkKnown("rowIds", it).add(rowId) + } + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [InsertEventsResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .rowIds() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): InsertEventsResponse = InsertEventsResponse( - rowIds.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable() + checkRequired("rowIds", rowIds).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): InsertEventsResponse = apply { + if (validated) { + return@apply + } + + rowIds() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (rowIds.asKnown()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InsertEventsResponse && + rowIds == other.rowIds && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(rowIds, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InsertEventsResponse{rowIds=$rowIds, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEvent.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEvent.kt new file mode 100644 index 00000000..4d860512 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEvent.kt @@ -0,0 +1,2034 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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.util.Collections +import java.util.Objects + +/** An experiment event */ +class InsertExperimentEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val _isMerge: JsonField, + private val _mergePaths: JsonField>>, + private val _objectDelete: JsonField, + private val _parentId: JsonField, + private val context: JsonField, + private val created: JsonField, + private val error: JsonValue, + private val expected: JsonValue, + private val input: JsonValue, + private val metadata: JsonField, + private val metrics: JsonField, + private val origin: JsonField, + private val output: JsonValue, + private val rootSpanId: JsonField, + private val scores: JsonField, + private val spanAttributes: JsonField, + private val spanId: JsonField, + private val spanParents: JsonField>, + private val tags: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_is_merge") @ExcludeMissing _isMerge: JsonField = JsonMissing.of(), + @JsonProperty("_merge_paths") + @ExcludeMissing + _mergePaths: JsonField>> = JsonMissing.of(), + @JsonProperty("_object_delete") + @ExcludeMissing + _objectDelete: JsonField = JsonMissing.of(), + @JsonProperty("_parent_id") @ExcludeMissing _parentId: JsonField = JsonMissing.of(), + @JsonProperty("context") @ExcludeMissing context: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonValue = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonValue = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("metrics") @ExcludeMissing metrics: JsonField = JsonMissing.of(), + @JsonProperty("origin") + @ExcludeMissing + origin: JsonField = JsonMissing.of(), + @JsonProperty("output") @ExcludeMissing output: JsonValue = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + @JsonProperty("span_attributes") + @ExcludeMissing + spanAttributes: JsonField = JsonMissing.of(), + @JsonProperty("span_id") @ExcludeMissing spanId: JsonField = JsonMissing.of(), + @JsonProperty("span_parents") + @ExcludeMissing + spanParents: JsonField> = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _isMerge, + _mergePaths, + _objectDelete, + _parentId, + context, + created, + error, + expected, + input, + metadata, + metrics, + origin, + output, + rootSpanId, + scores, + spanAttributes, + spanId, + spanParents, + tags, + mutableMapOf(), + ) + + /** + * A unique identifier for the experiment event. If you don't provide one, BrainTrust will + * generate one for you + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun id(): String? = id.getNullable("id") + + /** + * The `_is_merge` field controls how the row is merged with any existing row with the same id + * in the DB. By default (or when set to `false`), the existing row is completely replaced by + * the new row. When set to `true`, the new row is deep-merged into the existing row, if one is + * found. If no existing row is found, the new row is inserted as is. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": + * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": + * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we + * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be + * `{"id": "foo", "input": {"b": 11, "c": 20}}` + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _isMerge(): Boolean? = _isMerge.getNullable("_is_merge") + + /** + * The `_merge_paths` field allows controlling the depth of the merge, when `_is_merge=true`. + * `_merge_paths` is a list of paths, where each path is a list of field names. The deep merge + * will not descend below any of the specified merge paths. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, + * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, + * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, + * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": + * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the + * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and + * `input.c`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _mergePaths(): List>? = _mergePaths.getNullable("_merge_paths") + + /** + * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not show + * up in subsequent fetches for this experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") + + /** + * DEPRECATED: The `_parent_id` field is deprecated and should not be used. Support for + * `_parent_id` will be dropped in a future version of Braintrust. Log `span_id`, + * `root_span_id`, and `span_parents` explicitly instead. + * + * Use the `_parent_id` field to create this row as a subspan of an existing row. Tracking + * hierarchical relationships are important for tracing (see the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). + * + * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", + * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent + * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after + * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row + * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this + * case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _parentId(): String? = _parentId.getNullable("_parent_id") + + /** + * Context is additional information about the code that produced the experiment event. It is + * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the + * location in code which produced the experiment event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun context(): Context? = context.getNullable("context") + + /** + * The timestamp the experiment event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") + + /** The error that occurred, if any. */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonValue = error + + /** + * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to + * `output` to determine if your `output` value is correct or not. Braintrust currently does not + * compare `output` to `expected` for you, since there are so many different ways to do that + * correctly. Instead, these values are just used to help you navigate your experiments while + * digging into analyses. However, we may later use these values to re-score outputs or + * fine-tune your models + */ + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected + + /** + * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). + * Later on, Braintrust will use the `input` to know whether two test cases are the same between + * experiments, so they should not contain experiment-specific state. A simple rule of thumb is + * that if you run the same experiment twice, the `input` should be identical + */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonValue = input + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. For + * example, you could log the `prompt`, example's `id`, or anything else that would be useful to + * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys + * must be strings + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + + /** + * Metrics are numerical measurements tracking the execution of the code that produced the + * experiment event. Use "start" and "end" to track the time span over which the experiment + * event was produced + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metrics(): Metrics? = metrics.getNullable("metrics") + + /** + * Indicates the event was copied from another object. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun origin(): ObjectReference? = origin.getNullable("origin") + + /** + * The output of your application, including post-processing (an arbitrary, JSON serializable + * object), that allows you to determine whether the result is correct or not. For example, in + * an app that generates SQL queries, the `output` should be the _result_ of the SQL query + * generated by the model, not the query itself, because there may be multiple valid queries + * that answer a single question + */ + @JsonProperty("output") @ExcludeMissing fun _output(): JsonValue = output + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun rootSpanId(): String? = rootSpanId.getNullable("root_span_id") + + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare experiments + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun scores(): Scores? = scores.getNullable("scores") + + /** + * Human-identifying attributes of the span, such as name, type, etc. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanId(): String? = spanId.getNullable("span_id") + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanParents(): List? = spanParents.getNullable("span_parents") + + /** + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") + + /** + * 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 [_isMerge]. + * + * Unlike [_isMerge], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge(): JsonField = _isMerge + + /** + * Returns the raw JSON value of [_mergePaths]. + * + * Unlike [_mergePaths], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_merge_paths") + @ExcludeMissing + fun __mergePaths(): JsonField>> = _mergePaths + + /** + * Returns the raw JSON value of [_objectDelete]. + * + * Unlike [_objectDelete], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_object_delete") + @ExcludeMissing + fun __objectDelete(): JsonField = _objectDelete + + /** + * Returns the raw JSON value of [_parentId]. + * + * Unlike [_parentId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_parent_id") @ExcludeMissing fun __parentId(): JsonField = _parentId + + /** + * 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 [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * 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 [metrics]. + * + * Unlike [metrics], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metrics") @ExcludeMissing fun _metrics(): JsonField = metrics + + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin + + /** + * Returns the raw JSON value of [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId(): JsonField = rootSpanId + + /** + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores + + /** + * Returns the raw JSON value of [spanAttributes]. + * + * Unlike [spanAttributes], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_attributes") + @ExcludeMissing + fun _spanAttributes(): JsonField = spanAttributes + + /** + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId + + /** + * Returns the raw JSON value of [spanParents]. + * + * Unlike [spanParents], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_parents") + @ExcludeMissing + fun _spanParents(): JsonField> = spanParents + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags + + @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 [InsertExperimentEvent]. */ + fun builder() = Builder() + } + + /** A builder for [InsertExperimentEvent]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var _isMerge: JsonField = JsonMissing.of() + private var _mergePaths: JsonField>>? = null + private var _objectDelete: JsonField = JsonMissing.of() + private var _parentId: JsonField = JsonMissing.of() + private var context: JsonField = JsonMissing.of() + private var created: JsonField = JsonMissing.of() + private var error: JsonValue = JsonMissing.of() + private var expected: JsonValue = JsonMissing.of() + private var input: JsonValue = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var metrics: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var output: JsonValue = JsonMissing.of() + private var rootSpanId: JsonField = JsonMissing.of() + private var scores: JsonField = JsonMissing.of() + private var spanAttributes: JsonField = JsonMissing.of() + private var spanId: JsonField = JsonMissing.of() + private var spanParents: JsonField>? = null + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(insertExperimentEvent: InsertExperimentEvent) = apply { + id = insertExperimentEvent.id + _isMerge = insertExperimentEvent._isMerge + _mergePaths = insertExperimentEvent._mergePaths.map { it.toMutableList() } + _objectDelete = insertExperimentEvent._objectDelete + _parentId = insertExperimentEvent._parentId + context = insertExperimentEvent.context + created = insertExperimentEvent.created + error = insertExperimentEvent.error + expected = insertExperimentEvent.expected + input = insertExperimentEvent.input + metadata = insertExperimentEvent.metadata + metrics = insertExperimentEvent.metrics + origin = insertExperimentEvent.origin + output = insertExperimentEvent.output + rootSpanId = insertExperimentEvent.rootSpanId + scores = insertExperimentEvent.scores + spanAttributes = insertExperimentEvent.spanAttributes + spanId = insertExperimentEvent.spanId + spanParents = insertExperimentEvent.spanParents.map { it.toMutableList() } + tags = insertExperimentEvent.tags.map { it.toMutableList() } + additionalProperties = insertExperimentEvent.additionalProperties.toMutableMap() + } + + /** + * A unique identifier for the experiment event. If you don't provide one, BrainTrust will + * generate one for you + */ + fun id(id: String?) = id(JsonField.ofNullable(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 } + + /** + * The `_is_merge` field controls how the row is merged with any existing row with the same + * id in the DB. By default (or when set to `false`), the existing row is completely + * replaced by the new row. When set to `true`, the new row is deep-merged into the existing + * row, if one is found. If no existing row is found, the new row is inserted as is. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": + * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": + * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we + * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be + * `{"id": "foo", "input": {"b": 11, "c": 20}}` + */ + fun _isMerge(_isMerge: Boolean?) = _isMerge(JsonField.ofNullable(_isMerge)) + + /** + * Alias for [Builder._isMerge]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun _isMerge(_isMerge: Boolean) = _isMerge(_isMerge as Boolean?) + + /** + * Sets [Builder._isMerge] to an arbitrary JSON value. + * + * You should usually call [Builder._isMerge] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } + + /** + * The `_merge_paths` field allows controlling the depth of the merge, when + * `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of field + * names. The deep merge will not descend below any of the specified merge paths. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": + * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": + * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": + * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": + * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this + * case, due to the merge paths, we have replaced `input.a` and `output`, but have still + * deep-merged `input` and `input.c`. + */ + fun _mergePaths(_mergePaths: List>?) = + _mergePaths(JsonField.ofNullable(_mergePaths)) + + /** + * Sets [Builder._mergePaths] to an arbitrary JSON value. + * + * You should usually call [Builder._mergePaths] with a well-typed `List>` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun _mergePaths(_mergePaths: JsonField>>) = apply { + this._mergePaths = _mergePaths.map { it.toMutableList() } + } + + /** + * Adds a single [List] to [_mergePaths]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMergePath(mergePath: List) = apply { + _mergePaths = + (_mergePaths ?: JsonField.of(mutableListOf())).also { + checkKnown("_mergePaths", it).add(mergePath) + } + } + + /** + * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not + * show up in subsequent fetches for this experiment + */ + fun _objectDelete(_objectDelete: Boolean?) = + _objectDelete(JsonField.ofNullable(_objectDelete)) + + /** + * Alias for [Builder._objectDelete]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun _objectDelete(_objectDelete: Boolean) = _objectDelete(_objectDelete as Boolean?) + + /** + * Sets [Builder._objectDelete] to an arbitrary JSON value. + * + * You should usually call [Builder._objectDelete] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun _objectDelete(_objectDelete: JsonField) = apply { + this._objectDelete = _objectDelete + } + + /** + * DEPRECATED: The `_parent_id` field is deprecated and should not be used. Support for + * `_parent_id` will be dropped in a future version of Braintrust. Log `span_id`, + * `root_span_id`, and `span_parents` explicitly instead. + * + * Use the `_parent_id` field to create this row as a subspan of an existing row. Tracking + * hierarchical relationships are important for tracing (see the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). + * + * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", + * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the + * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the + * root span row `"abc"` will show up in the summary view. You can view the full trace + * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun _parentId(_parentId: String?) = _parentId(JsonField.ofNullable(_parentId)) + + /** + * Sets [Builder._parentId] to an arbitrary JSON value. + * + * You should usually call [Builder._parentId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _parentId(_parentId: JsonField) = apply { this._parentId = _parentId } + + /** + * Context is additional information about the code that produced the experiment event. It + * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to + * track the location in code which produced the experiment event + */ + fun context(context: Context?) = context(JsonField.ofNullable(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 } + + /** The timestamp the experiment event was created */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } + + /** The error that occurred, if any. */ + fun error(error: JsonValue) = apply { this.error = error } + + /** + * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to + * `output` to determine if your `output` value is correct or not. Braintrust currently does + * not compare `output` to `expected` for you, since there are so many different ways to do + * that correctly. Instead, these values are just used to help you navigate your experiments + * while digging into analyses. However, we may later use these values to re-score outputs + * or fine-tune your models + */ + fun expected(expected: JsonValue) = apply { this.expected = expected } + + /** + * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). + * Later on, Braintrust will use the `input` to know whether two test cases are the same + * between experiments, so they should not contain experiment-specific state. A simple rule + * of thumb is that if you run the same experiment twice, the `input` should be identical + */ + fun input(input: JsonValue) = apply { this.input = input } + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. + * For example, you could log the `prompt`, example's `id`, or anything else that would be + * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, + * but its keys must be strings + */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + + /** + * Metrics are numerical measurements tracking the execution of the code that produced the + * experiment event. Use "start" and "end" to track the time span over which the experiment + * event was produced + */ + fun metrics(metrics: Metrics?) = metrics(JsonField.ofNullable(metrics)) + + /** + * Sets [Builder.metrics] to an arbitrary JSON value. + * + * You should usually call [Builder.metrics] with a well-typed [Metrics] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun metrics(metrics: JsonField) = apply { this.metrics = metrics } + + /** Indicates the event was copied from another object. */ + fun origin(origin: ObjectReference?) = origin(JsonField.ofNullable(origin)) + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [ObjectReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun origin(origin: JsonField) = apply { this.origin = origin } + + /** + * The output of your application, including post-processing (an arbitrary, JSON + * serializable object), that allows you to determine whether the result is correct or not. + * For example, in an app that generates SQL queries, the `output` should be the _result_ of + * the SQL query generated by the model, not the query itself, because there may be multiple + * valid queries that answer a single question + */ + fun output(output: JsonValue) = apply { this.output = output } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun rootSpanId(rootSpanId: String?) = rootSpanId(JsonField.ofNullable(rootSpanId)) + + /** + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a + * variety of signals that help you determine how accurate the outputs are compared to what + * you expect and diagnose failures. For example, a summarization app might have one score + * that tells you how accurate the summary is, and another that measures the word similarity + * between the generated and grouth truth summary. The word similarity score could help you + * determine whether the summarization was covering similar concepts or not. You can use + * these scores to help you sort, filter, and compare experiments + */ + fun scores(scores: Scores?) = scores(JsonField.ofNullable(scores)) + + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun scores(scores: JsonField) = apply { this.scores = scores } + + /** Human-identifying attributes of the span, such as name, type, etc. */ + fun spanAttributes(spanAttributes: SpanAttributes?) = + spanAttributes(JsonField.ofNullable(spanAttributes)) + + /** + * Sets [Builder.spanAttributes] to an arbitrary JSON value. + * + * You should usually call [Builder.spanAttributes] with a well-typed [SpanAttributes] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun spanAttributes(spanAttributes: JsonField) = apply { + this.spanAttributes = spanAttributes + } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun spanId(spanId: String?) = spanId(JsonField.ofNullable(spanId)) + + /** + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun spanParents(spanParents: List?) = spanParents(JsonField.ofNullable(spanParents)) + + /** + * Sets [Builder.spanParents] to an arbitrary JSON value. + * + * You should usually call [Builder.spanParents] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun spanParents(spanParents: JsonField>) = apply { + this.spanParents = spanParents.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [spanParents]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSpanParent(spanParent: String) = apply { + spanParents = + (spanParents ?: JsonField.of(mutableListOf())).also { + checkKnown("spanParents", it).add(spanParent) + } + } + + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + + 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 [InsertExperimentEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): InsertExperimentEvent = + InsertExperimentEvent( + id, + _isMerge, + (_mergePaths ?: JsonMissing.of()).map { it.toImmutable() }, + _objectDelete, + _parentId, + context, + created, + error, + expected, + input, + metadata, + metrics, + origin, + output, + rootSpanId, + scores, + spanAttributes, + spanId, + (spanParents ?: JsonMissing.of()).map { it.toImmutable() }, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): InsertExperimentEvent = apply { + if (validated) { + return@apply + } + + id() + _isMerge() + _mergePaths() + _objectDelete() + _parentId() + context()?.validate() + created() + metadata()?.validate() + metrics()?.validate() + origin()?.validate() + rootSpanId() + scores()?.validate() + spanAttributes()?.validate() + spanId() + spanParents() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_isMerge.asKnown() == null) 0 else 1) + + (_mergePaths.asKnown()?.sumOf { it.size.toInt() } ?: 0) + + (if (_objectDelete.asKnown() == null) 0 else 1) + + (if (_parentId.asKnown() == null) 0 else 1) + + (context.asKnown()?.validity() ?: 0) + + (if (created.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (metrics.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (scores.asKnown()?.validity() ?: 0) + + (spanAttributes.asKnown()?.validity() ?: 0) + + (if (spanId.asKnown() == null) 0 else 1) + + (spanParents.asKnown()?.size ?: 0) + + (tags.asKnown()?.size ?: 0) + + /** + * Context is additional information about the code that produced the experiment event. It is + * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the + * location in code which produced the experiment event + */ + class Context + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val callerFilename: JsonField, + private val callerFunctionname: JsonField, + private val callerLineno: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonField = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonField = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonField = JsonMissing.of(), + ) : this(callerFilename, callerFunctionname, callerLineno, mutableMapOf()) + + /** + * Name of the file in code where the experiment event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerFilename(): String? = callerFilename.getNullable("caller_filename") + + /** + * The function in code which created the experiment event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") + + /** + * Line of code where the experiment event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") + + /** + * Returns the raw JSON value of [callerFilename]. + * + * Unlike [callerFilename], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonField = callerFilename + + /** + * Returns the raw JSON value of [callerFunctionname]. + * + * Unlike [callerFunctionname], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("caller_functionname") + @ExcludeMissing + fun _callerFunctionname(): JsonField = callerFunctionname + + /** + * Returns the raw JSON value of [callerLineno]. + * + * Unlike [callerLineno], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_lineno") + @ExcludeMissing + fun _callerLineno(): JsonField = callerLineno + + @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]. */ + fun builder() = Builder() + } + + /** A builder for [Context]. */ + class Builder internal constructor() { + + private var callerFilename: JsonField = JsonMissing.of() + private var callerFunctionname: JsonField = JsonMissing.of() + private var callerLineno: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(context: Context) = apply { + callerFilename = context.callerFilename + callerFunctionname = context.callerFunctionname + callerLineno = context.callerLineno + additionalProperties = context.additionalProperties.toMutableMap() + } + + /** Name of the file in code where the experiment event was created */ + fun callerFilename(callerFilename: String?) = + callerFilename(JsonField.ofNullable(callerFilename)) + + /** + * Sets [Builder.callerFilename] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFilename] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerFilename(callerFilename: JsonField) = apply { + this.callerFilename = callerFilename + } + + /** The function in code which created the experiment event */ + fun callerFunctionname(callerFunctionname: String?) = + callerFunctionname(JsonField.ofNullable(callerFunctionname)) + + /** + * Sets [Builder.callerFunctionname] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFunctionname] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerFunctionname(callerFunctionname: JsonField) = apply { + this.callerFunctionname = callerFunctionname + } + + /** Line of code where the experiment event was created */ + fun callerLineno(callerLineno: Long?) = callerLineno(JsonField.ofNullable(callerLineno)) + + /** + * Alias for [Builder.callerLineno]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun callerLineno(callerLineno: Long) = callerLineno(callerLineno as Long?) + + /** + * Sets [Builder.callerLineno] to an arbitrary JSON value. + * + * You should usually call [Builder.callerLineno] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerLineno(callerLineno: JsonField) = apply { + this.callerLineno = callerLineno + } + + 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. + */ + fun build(): Context = + Context( + callerFilename, + callerFunctionname, + callerLineno, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Context = apply { + if (validated) { + return@apply + } + + callerFilename() + callerFunctionname() + callerLineno() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (callerFilename.asKnown() == null) 0 else 1) + + (if (callerFunctionname.asKnown() == null) 0 else 1) + + (if (callerLineno.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Context && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(callerFilename, callerFunctionname, callerLineno, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Context{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" + } + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. For + * example, you could log the `prompt`, example's `id`, or anything else that would be useful to + * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys + * must be strings + */ + class Metadata + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of() + ) : this(model, mutableMapOf()) + + /** + * The model used for this example + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): String? = model.getNullable("model") + + /** + * 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 + + @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 [Metadata]. */ + fun builder() = Builder() + } + + /** A builder for [Metadata]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(metadata: Metadata) = apply { + model = metadata.model + additionalProperties = metadata.additionalProperties.toMutableMap() + } + + /** The model used for this example */ + fun model(model: String?) = model(JsonField.ofNullable(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 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(model, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + model() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (model.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && + model == other.model && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(model, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metadata{model=$model, additionalProperties=$additionalProperties}" + } + + /** + * Metrics are numerical measurements tracking the execution of the code that produced the + * experiment event. Use "start" and "end" to track the time span over which the experiment + * event was produced + */ + class Metrics + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val callerFilename: JsonValue, + private val callerFunctionname: JsonValue, + private val callerLineno: JsonValue, + private val completionTokens: JsonField, + private val end: JsonField, + private val promptTokens: JsonField, + private val start: JsonField, + private val tokens: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonValue = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonValue = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonValue = JsonMissing.of(), + @JsonProperty("completion_tokens") + @ExcludeMissing + completionTokens: JsonField = JsonMissing.of(), + @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), + @JsonProperty("prompt_tokens") + @ExcludeMissing + promptTokens: JsonField = JsonMissing.of(), + @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), + @JsonProperty("tokens") @ExcludeMissing tokens: JsonField = JsonMissing.of(), + ) : this( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + mutableMapOf(), + ) + + /** This metric is deprecated */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonValue = callerFilename + + /** This metric is deprecated */ + @JsonProperty("caller_functionname") + @ExcludeMissing + fun _callerFunctionname(): JsonValue = callerFunctionname + + /** This metric is deprecated */ + @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno(): JsonValue = callerLineno + + /** + * The number of tokens in the completion generated by the model (only set if this is an LLM + * span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") + + /** + * A unix timestamp recording when the section of code which produced the experiment event + * finished + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun end(): Double? = end.getNullable("end") + + /** + * The number of tokens in the prompt used to generate the experiment event (only set if + * this is an LLM span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") + + /** + * A unix timestamp recording when the section of code which produced the experiment event + * started + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun start(): Double? = start.getNullable("start") + + /** + * The total number of tokens in the input and output of the experiment event. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tokens(): Long? = tokens.getNullable("tokens") + + /** + * Returns the raw JSON value of [completionTokens]. + * + * Unlike [completionTokens], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("completion_tokens") + @ExcludeMissing + fun _completionTokens(): JsonField = completionTokens + + /** + * Returns the raw JSON value of [end]. + * + * Unlike [end], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end + + /** + * Returns the raw JSON value of [promptTokens]. + * + * Unlike [promptTokens], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("prompt_tokens") + @ExcludeMissing + fun _promptTokens(): JsonField = promptTokens + + /** + * Returns the raw JSON value of [start]. + * + * Unlike [start], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start + + /** + * Returns the raw JSON value of [tokens]. + * + * Unlike [tokens], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tokens") @ExcludeMissing fun _tokens(): JsonField = tokens + + @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 [Metrics]. */ + fun builder() = Builder() + } + + /** A builder for [Metrics]. */ + class Builder internal constructor() { + + private var callerFilename: JsonValue = JsonMissing.of() + private var callerFunctionname: JsonValue = JsonMissing.of() + private var callerLineno: JsonValue = JsonMissing.of() + private var completionTokens: JsonField = JsonMissing.of() + private var end: JsonField = JsonMissing.of() + private var promptTokens: JsonField = JsonMissing.of() + private var start: JsonField = JsonMissing.of() + private var tokens: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(metrics: Metrics) = apply { + callerFilename = metrics.callerFilename + callerFunctionname = metrics.callerFunctionname + callerLineno = metrics.callerLineno + completionTokens = metrics.completionTokens + end = metrics.end + promptTokens = metrics.promptTokens + start = metrics.start + tokens = metrics.tokens + additionalProperties = metrics.additionalProperties.toMutableMap() + } + + /** This metric is deprecated */ + fun callerFilename(callerFilename: JsonValue) = apply { + this.callerFilename = callerFilename + } + + /** This metric is deprecated */ + fun callerFunctionname(callerFunctionname: JsonValue) = apply { + this.callerFunctionname = callerFunctionname + } + + /** This metric is deprecated */ + fun callerLineno(callerLineno: JsonValue) = apply { this.callerLineno = callerLineno } + + /** + * The number of tokens in the completion generated by the model (only set if this is an + * LLM span) + */ + fun completionTokens(completionTokens: Long?) = + completionTokens(JsonField.ofNullable(completionTokens)) + + /** + * Alias for [Builder.completionTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun completionTokens(completionTokens: Long) = + completionTokens(completionTokens as Long?) + + /** + * Sets [Builder.completionTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.completionTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun completionTokens(completionTokens: JsonField) = apply { + this.completionTokens = completionTokens + } + + /** + * A unix timestamp recording when the section of code which produced the experiment + * event finished + */ + fun end(end: Double?) = end(JsonField.ofNullable(end)) + + /** + * Alias for [Builder.end]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun end(end: Double) = end(end as Double?) + + /** + * Sets [Builder.end] to an arbitrary JSON value. + * + * You should usually call [Builder.end] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun end(end: JsonField) = apply { this.end = end } + + /** + * The number of tokens in the prompt used to generate the experiment event (only set if + * this is an LLM span) + */ + fun promptTokens(promptTokens: Long?) = promptTokens(JsonField.ofNullable(promptTokens)) + + /** + * Alias for [Builder.promptTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun promptTokens(promptTokens: Long) = promptTokens(promptTokens as Long?) + + /** + * Sets [Builder.promptTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.promptTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptTokens(promptTokens: JsonField) = apply { + this.promptTokens = promptTokens + } + + /** + * A unix timestamp recording when the section of code which produced the experiment + * event started + */ + fun start(start: Double?) = start(JsonField.ofNullable(start)) + + /** + * Alias for [Builder.start]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun start(start: Double) = start(start as Double?) + + /** + * Sets [Builder.start] to an arbitrary JSON value. + * + * You should usually call [Builder.start] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun start(start: JsonField) = apply { this.start = start } + + /** The total number of tokens in the input and output of the experiment event. */ + fun tokens(tokens: Long?) = tokens(JsonField.ofNullable(tokens)) + + /** + * Alias for [Builder.tokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun tokens(tokens: Long) = tokens(tokens as Long?) + + /** + * Sets [Builder.tokens] to an arbitrary JSON value. + * + * You should usually call [Builder.tokens] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tokens(tokens: JsonField) = apply { this.tokens = tokens } + + 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 [Metrics]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Metrics = + Metrics( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Metrics = apply { + if (validated) { + return@apply + } + + completionTokens() + end() + promptTokens() + start() + tokens() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (completionTokens.asKnown() == null) 0 else 1) + + (if (end.asKnown() == null) 0 else 1) + + (if (promptTokens.asKnown() == null) 0 else 1) + + (if (start.asKnown() == null) 0 else 1) + + (if (tokens.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metrics && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + completionTokens == other.completionTokens && + end == other.end && + promptTokens == other.promptTokens && + start == other.start && + tokens == other.tokens && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metrics{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, completionTokens=$completionTokens, end=$end, promptTokens=$promptTokens, start=$start, tokens=$tokens, additionalProperties=$additionalProperties}" + } + + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare experiments + */ + class Scores + @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 [Scores]. */ + fun builder() = Builder() + } + + /** A builder for [Scores]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(scores: Scores) = apply { + additionalProperties = scores.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 [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Scores = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Scores && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Scores{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InsertExperimentEvent && + id == other.id && + _isMerge == other._isMerge && + _mergePaths == other._mergePaths && + _objectDelete == other._objectDelete && + _parentId == other._parentId && + context == other.context && + created == other.created && + error == other.error && + expected == other.expected && + input == other.input && + metadata == other.metadata && + metrics == other.metrics && + origin == other.origin && + output == other.output && + rootSpanId == other.rootSpanId && + scores == other.scores && + spanAttributes == other.spanAttributes && + spanId == other.spanId && + spanParents == other.spanParents && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + _isMerge, + _mergePaths, + _objectDelete, + _parentId, + context, + created, + error, + expected, + input, + metadata, + metrics, + origin, + output, + rootSpanId, + scores, + spanAttributes, + spanId, + spanParents, + tags, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InsertExperimentEvent{id=$id, _isMerge=$_isMerge, _mergePaths=$_mergePaths, _objectDelete=$_objectDelete, _parentId=$_parentId, context=$context, created=$created, error=$error, expected=$expected, input=$input, metadata=$metadata, metrics=$metrics, origin=$origin, output=$output, rootSpanId=$rootSpanId, scores=$scores, spanAttributes=$spanAttributes, spanId=$spanId, spanParents=$spanParents, tags=$tags, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEventMerge.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEventMerge.kt deleted file mode 100755 index ee83bf28..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEventMerge.kt +++ /dev/null @@ -1,1462 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.databind.annotation.JsonDeserialize -import java.time.OffsetDateTime -import java.util.Objects - -@JsonDeserialize(builder = InsertExperimentEventMerge.Builder::class) -@NoAutoDetect -class InsertExperimentEventMerge -private constructor( - private val input: JsonValue, - private val output: JsonValue, - private val expected: JsonValue, - private val error: JsonValue, - private val scores: JsonField, - private val metadata: JsonField, - private val tags: JsonField>, - private val metrics: JsonField, - private val context: JsonField, - private val spanAttributes: JsonField, - private val id: JsonField, - private val datasetRecordId: JsonField, - private val created: JsonField, - private val _objectDelete: JsonField, - private val _isMerge: JsonField, - private val _mergePaths: JsonField>>, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same between - * experiments, so they should not contain experiment-specific state. A simple rule of thumb is - * that if you run the same experiment twice, the `input` should be identical - */ - fun input(): JsonValue = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question - */ - fun output(): JsonValue = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate your experiments while - * digging into analyses. However, we may later use these values to re-score outputs or - * fine-tune your models - */ - fun expected(): JsonValue = expected - - /** The error that occurred, if any. */ - fun error(): JsonValue = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments - */ - fun scores(): Scores? = scores.getNullable("scores") - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - fun metadata(): Metadata? = metadata.getNullable("metadata") - - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - fun metrics(): Metrics? = metrics.getNullable("metrics") - - /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event - */ - fun context(): Context? = context.getNullable("context") - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(): String? = id.getNullable("id") - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - fun datasetRecordId(): String? = datasetRecordId.getNullable("dataset_record_id") - - /** The timestamp the experiment event was created */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not show - * up in subsequent fetches for this experiment - */ - fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(): Boolean = _isMerge.getRequired("_is_merge") - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be specified - * alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of - * field names. The deep merge will not descend below any of the specified merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, - * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, - * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, - * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": - * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the - * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and - * `input.c`. - */ - fun _mergePaths(): List>? = _mergePaths.getNullable("_merge_paths") - - /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same between - * experiments, so they should not contain experiment-specific state. A simple rule of thumb is - * that if you run the same experiment twice, the `input` should be identical - */ - @JsonProperty("input") @ExcludeMissing fun _input() = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question - */ - @JsonProperty("output") @ExcludeMissing fun _output() = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate your experiments while - * digging into analyses. However, we may later use these values to re-score outputs or - * fine-tune your models - */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected - - /** The error that occurred, if any. */ - @JsonProperty("error") @ExcludeMissing fun _error() = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments - */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - @JsonProperty("metrics") @ExcludeMissing fun _metrics() = metrics - - /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event - */ - @JsonProperty("context") @ExcludeMissing fun _context() = context - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") @ExcludeMissing fun _spanAttributes() = spanAttributes - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - @JsonProperty("dataset_record_id") @ExcludeMissing fun _datasetRecordId() = datasetRecordId - - /** The timestamp the experiment event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not show - * up in subsequent fetches for this experiment - */ - @JsonProperty("_object_delete") @ExcludeMissing fun __objectDelete() = _objectDelete - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge() = _isMerge - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be specified - * alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of - * field names. The deep merge will not descend below any of the specified merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, - * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, - * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, - * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": - * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the - * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and - * `input.c`. - */ - @JsonProperty("_merge_paths") @ExcludeMissing fun __mergePaths() = _mergePaths - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InsertExperimentEventMerge = apply { - if (!validated) { - input() - output() - expected() - error() - scores()?.validate() - metadata()?.validate() - tags() - metrics()?.validate() - context()?.validate() - spanAttributes()?.validate() - id() - datasetRecordId() - created() - _objectDelete() - _isMerge() - _mergePaths() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InsertExperimentEventMerge && - this.input == other.input && - this.output == other.output && - this.expected == other.expected && - this.error == other.error && - this.scores == other.scores && - this.metadata == other.metadata && - this.tags == other.tags && - this.metrics == other.metrics && - this.context == other.context && - this.spanAttributes == other.spanAttributes && - this.id == other.id && - this.datasetRecordId == other.datasetRecordId && - this.created == other.created && - this._objectDelete == other._objectDelete && - this._isMerge == other._isMerge && - this._mergePaths == other._mergePaths && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - input, - output, - expected, - error, - scores, - metadata, - tags, - metrics, - context, - spanAttributes, - id, - datasetRecordId, - created, - _objectDelete, - _isMerge, - _mergePaths, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InsertExperimentEventMerge{input=$input, output=$output, expected=$expected, error=$error, scores=$scores, metadata=$metadata, tags=$tags, metrics=$metrics, context=$context, spanAttributes=$spanAttributes, id=$id, datasetRecordId=$datasetRecordId, created=$created, _objectDelete=$_objectDelete, _isMerge=$_isMerge, _mergePaths=$_mergePaths, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var input: JsonValue = JsonMissing.of() - private var output: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() - private var error: JsonValue = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var metrics: JsonField = JsonMissing.of() - private var context: JsonField = JsonMissing.of() - private var spanAttributes: JsonField = JsonMissing.of() - private var id: JsonField = JsonMissing.of() - private var datasetRecordId: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var _objectDelete: JsonField = JsonMissing.of() - private var _isMerge: JsonField = JsonMissing.of() - private var _mergePaths: JsonField>> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(insertExperimentEventMerge: InsertExperimentEventMerge) = apply { - this.input = insertExperimentEventMerge.input - this.output = insertExperimentEventMerge.output - this.expected = insertExperimentEventMerge.expected - this.error = insertExperimentEventMerge.error - this.scores = insertExperimentEventMerge.scores - this.metadata = insertExperimentEventMerge.metadata - this.tags = insertExperimentEventMerge.tags - this.metrics = insertExperimentEventMerge.metrics - this.context = insertExperimentEventMerge.context - this.spanAttributes = insertExperimentEventMerge.spanAttributes - this.id = insertExperimentEventMerge.id - this.datasetRecordId = insertExperimentEventMerge.datasetRecordId - this.created = insertExperimentEventMerge.created - this._objectDelete = insertExperimentEventMerge._objectDelete - this._isMerge = insertExperimentEventMerge._isMerge - this._mergePaths = insertExperimentEventMerge._mergePaths - additionalProperties(insertExperimentEventMerge.additionalProperties) - } - - /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same - * between experiments, so they should not contain experiment-specific state. A simple rule - * of thumb is that if you run the same experiment twice, the `input` should be identical - */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } - - /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object), that allows you to determine whether the result is correct or not. - * For example, in an app that generates SQL queries, the `output` should be the _result_ of - * the SQL query generated by the model, not the query itself, because there may be multiple - * valid queries that answer a single question - */ - @JsonProperty("output") - @ExcludeMissing - fun output(output: JsonValue) = apply { this.output = output } - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does - * not compare `output` to `expected` for you, since there are so many different ways to do - * that correctly. Instead, these values are just used to help you navigate your experiments - * while digging into analyses. However, we may later use these values to re-score outputs - * or fine-tune your models - */ - @JsonProperty("expected") - @ExcludeMissing - fun expected(expected: JsonValue) = apply { this.expected = expected } - - /** The error that occurred, if any. */ - @JsonProperty("error") - @ExcludeMissing - fun error(error: JsonValue) = apply { this.error = error } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare experiments - */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare experiments - */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - fun metrics(metrics: Metrics) = metrics(JsonField.of(metrics)) - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - @JsonProperty("metrics") - @ExcludeMissing - fun metrics(metrics: JsonField) = apply { this.metrics = metrics } - - /** - * Context is additional information about the code that produced the experiment event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the experiment event - */ - fun context(context: Context) = context(JsonField.of(context)) - - /** - * Context is additional information about the code that produced the experiment event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the experiment event - */ - @JsonProperty("context") - @ExcludeMissing - fun context(context: JsonField) = apply { this.context = context } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(spanAttributes: SpanAttributes) = - spanAttributes(JsonField.of(spanAttributes)) - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") - @ExcludeMissing - fun spanAttributes(spanAttributes: JsonField) = apply { - this.spanAttributes = spanAttributes - } - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(id: String) = id(JsonField.of(id)) - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - fun datasetRecordId(datasetRecordId: String) = - datasetRecordId(JsonField.of(datasetRecordId)) - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - @JsonProperty("dataset_record_id") - @ExcludeMissing - fun datasetRecordId(datasetRecordId: JsonField) = apply { - this.datasetRecordId = datasetRecordId - } - - /** The timestamp the experiment event was created */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** The timestamp the experiment event was created */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not - * show up in subsequent fetches for this experiment - */ - fun _objectDelete(_objectDelete: Boolean) = _objectDelete(JsonField.of(_objectDelete)) - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not - * show up in subsequent fetches for this experiment - */ - @JsonProperty("_object_delete") - @ExcludeMissing - fun _objectDelete(_objectDelete: JsonField) = apply { - this._objectDelete = _objectDelete - } - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(_isMerge: Boolean) = _isMerge(JsonField.of(_isMerge)) - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") - @ExcludeMissing - fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be - * specified alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path - * is a list of field names. The deep merge will not descend below any of the specified - * merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": - * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": - * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": - * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": - * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this - * case, due to the merge paths, we have replaced `input.a` and `output`, but have still - * deep-merged `input` and `input.c`. - */ - fun _mergePaths(_mergePaths: List>) = _mergePaths(JsonField.of(_mergePaths)) - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be - * specified alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path - * is a list of field names. The deep merge will not descend below any of the specified - * merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": - * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": - * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": - * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": - * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this - * case, due to the merge paths, we have replaced `input.a` and `output`, but have still - * deep-merged `input` and `input.c`. - */ - @JsonProperty("_merge_paths") - @ExcludeMissing - fun _mergePaths(_mergePaths: JsonField>>) = apply { - this._mergePaths = _mergePaths - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): InsertExperimentEventMerge = - InsertExperimentEventMerge( - input, - output, - expected, - error, - scores, - metadata, - tags.map { it.toUnmodifiable() }, - metrics, - context, - spanAttributes, - id, - datasetRecordId, - created, - _objectDelete, - _isMerge, - _mergePaths.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), - ) - } - - /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event - */ - @JsonDeserialize(builder = Context.Builder::class) - @NoAutoDetect - class Context - private constructor( - private val callerFunctionname: JsonField, - private val callerFilename: JsonField, - private val callerLineno: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The function in code which created the experiment event */ - fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") - - /** Name of the file in code where the experiment event was created */ - fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - - /** Line of code where the experiment event was created */ - fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") - - /** The function in code which created the experiment event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun _callerFunctionname() = callerFunctionname - - /** Name of the file in code where the experiment event was created */ - @JsonProperty("caller_filename") @ExcludeMissing fun _callerFilename() = callerFilename - - /** Line of code where the experiment event was created */ - @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno() = callerLineno - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Context = apply { - if (!validated) { - callerFunctionname() - callerFilename() - callerLineno() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Context && - this.callerFunctionname == other.callerFunctionname && - this.callerFilename == other.callerFilename && - this.callerLineno == other.callerLineno && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Context{callerFunctionname=$callerFunctionname, callerFilename=$callerFilename, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var callerFunctionname: JsonField = JsonMissing.of() - private var callerFilename: JsonField = JsonMissing.of() - private var callerLineno: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(context: Context) = apply { - this.callerFunctionname = context.callerFunctionname - this.callerFilename = context.callerFilename - this.callerLineno = context.callerLineno - additionalProperties(context.additionalProperties) - } - - /** The function in code which created the experiment event */ - fun callerFunctionname(callerFunctionname: String) = - callerFunctionname(JsonField.of(callerFunctionname)) - - /** The function in code which created the experiment event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun callerFunctionname(callerFunctionname: JsonField) = apply { - this.callerFunctionname = callerFunctionname - } - - /** Name of the file in code where the experiment event was created */ - fun callerFilename(callerFilename: String) = - callerFilename(JsonField.of(callerFilename)) - - /** Name of the file in code where the experiment event was created */ - @JsonProperty("caller_filename") - @ExcludeMissing - fun callerFilename(callerFilename: JsonField) = apply { - this.callerFilename = callerFilename - } - - /** Line of code where the experiment event was created */ - fun callerLineno(callerLineno: Long) = callerLineno(JsonField.of(callerLineno)) - - /** Line of code where the experiment event was created */ - @JsonProperty("caller_lineno") - @ExcludeMissing - fun callerLineno(callerLineno: JsonField) = apply { - this.callerLineno = callerLineno - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Context = - Context( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - @JsonDeserialize(builder = Metrics.Builder::class) - @NoAutoDetect - class Metrics - private constructor( - private val start: JsonField, - private val end: JsonField, - private val promptTokens: JsonField, - private val completionTokens: JsonField, - private val tokens: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * started - */ - fun start(): Double? = start.getNullable("start") - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * finished - */ - fun end(): Double? = end.getNullable("end") - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") - - /** The total number of tokens in the input and output of the experiment event. */ - fun tokens(): Long? = tokens.getNullable("tokens") - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * started - */ - @JsonProperty("start") @ExcludeMissing fun _start() = start - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * finished - */ - @JsonProperty("end") @ExcludeMissing fun _end() = end - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - @JsonProperty("prompt_tokens") @ExcludeMissing fun _promptTokens() = promptTokens - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun _completionTokens() = completionTokens - - /** The total number of tokens in the input and output of the experiment event. */ - @JsonProperty("tokens") @ExcludeMissing fun _tokens() = tokens - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metrics = apply { - if (!validated) { - start() - end() - promptTokens() - completionTokens() - tokens() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metrics && - this.start == other.start && - this.end == other.end && - this.promptTokens == other.promptTokens && - this.completionTokens == other.completionTokens && - this.tokens == other.tokens && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Metrics{start=$start, end=$end, promptTokens=$promptTokens, completionTokens=$completionTokens, tokens=$tokens, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var start: JsonField = JsonMissing.of() - private var end: JsonField = JsonMissing.of() - private var promptTokens: JsonField = JsonMissing.of() - private var completionTokens: JsonField = JsonMissing.of() - private var tokens: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metrics: Metrics) = apply { - this.start = metrics.start - this.end = metrics.end - this.promptTokens = metrics.promptTokens - this.completionTokens = metrics.completionTokens - this.tokens = metrics.tokens - additionalProperties(metrics.additionalProperties) - } - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event started - */ - fun start(start: Double) = start(JsonField.of(start)) - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event started - */ - @JsonProperty("start") - @ExcludeMissing - fun start(start: JsonField) = apply { this.start = start } - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event finished - */ - fun end(end: Double) = end(JsonField.of(end)) - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event finished - */ - @JsonProperty("end") - @ExcludeMissing - fun end(end: JsonField) = apply { this.end = end } - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - fun promptTokens(promptTokens: Long) = promptTokens(JsonField.of(promptTokens)) - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - @JsonProperty("prompt_tokens") - @ExcludeMissing - fun promptTokens(promptTokens: JsonField) = apply { - this.promptTokens = promptTokens - } - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - fun completionTokens(completionTokens: Long) = - completionTokens(JsonField.of(completionTokens)) - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun completionTokens(completionTokens: JsonField) = apply { - this.completionTokens = completionTokens - } - - /** The total number of tokens in the input and output of the experiment event. */ - fun tokens(tokens: Long) = tokens(JsonField.of(tokens)) - - /** The total number of tokens in the input and output of the experiment event. */ - @JsonProperty("tokens") - @ExcludeMissing - fun tokens(tokens: JsonField) = apply { this.tokens = tokens } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metrics = - Metrics( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Scores = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Scores && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Scores{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) - } - } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonDeserialize(builder = SpanAttributes.Builder::class) - @NoAutoDetect - class SpanAttributes - private constructor( - private val name: JsonField, - private val type: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Name of the span, for display purposes only */ - fun name(): String? = name.getNullable("name") - - /** Type of the span, for display purposes only */ - fun type(): Type? = type.getNullable("type") - - /** Name of the span, for display purposes only */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Type of the span, for display purposes only */ - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): SpanAttributes = apply { - if (!validated) { - name() - type() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SpanAttributes && - this.name == other.name && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SpanAttributes{name=$name, type=$type, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var name: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(spanAttributes: SpanAttributes) = apply { - this.name = spanAttributes.name - this.type = spanAttributes.type - additionalProperties(spanAttributes.additionalProperties) - } - - /** Name of the span, for display purposes only */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the span, for display purposes only */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - /** Type of the span, for display purposes only */ - fun type(type: Type) = type(JsonField.of(type)) - - /** Type of the span, for display purposes only */ - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): SpanAttributes = - SpanAttributes( - name, - type, - additionalProperties.toUnmodifiable(), - ) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val LLM = Type(JsonField.of("llm")) - - val SCORE = Type(JsonField.of("score")) - - val FUNCTION = Type(JsonField.of("function")) - - val EVAL = Type(JsonField.of("eval")) - - val TASK = Type(JsonField.of("task")) - - val TOOL = Type(JsonField.of("tool")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - } - - enum class Value { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - LLM -> Value.LLM - SCORE -> Value.SCORE - FUNCTION -> Value.FUNCTION - EVAL -> Value.EVAL - TASK -> Value.TASK - TOOL -> Value.TOOL - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - LLM -> Known.LLM - SCORE -> Known.SCORE - FUNCTION -> Known.FUNCTION - EVAL -> Known.EVAL - TASK -> Known.TASK - TOOL -> Known.TOOL - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEventReplace.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEventReplace.kt deleted file mode 100755 index 00fb6d90..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertExperimentEventReplace.kt +++ /dev/null @@ -1,1456 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.databind.annotation.JsonDeserialize -import java.time.OffsetDateTime -import java.util.Objects - -@JsonDeserialize(builder = InsertExperimentEventReplace.Builder::class) -@NoAutoDetect -class InsertExperimentEventReplace -private constructor( - private val input: JsonValue, - private val output: JsonValue, - private val expected: JsonValue, - private val error: JsonValue, - private val scores: JsonField, - private val metadata: JsonField, - private val tags: JsonField>, - private val metrics: JsonField, - private val context: JsonField, - private val spanAttributes: JsonField, - private val id: JsonField, - private val datasetRecordId: JsonField, - private val created: JsonField, - private val _objectDelete: JsonField, - private val _isMerge: JsonField, - private val _parentId: JsonField, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same between - * experiments, so they should not contain experiment-specific state. A simple rule of thumb is - * that if you run the same experiment twice, the `input` should be identical - */ - fun input(): JsonValue = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question - */ - fun output(): JsonValue = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate your experiments while - * digging into analyses. However, we may later use these values to re-score outputs or - * fine-tune your models - */ - fun expected(): JsonValue = expected - - /** The error that occurred, if any. */ - fun error(): JsonValue = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments - */ - fun scores(): Scores? = scores.getNullable("scores") - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - fun metadata(): Metadata? = metadata.getNullable("metadata") - - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - fun metrics(): Metrics? = metrics.getNullable("metrics") - - /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event - */ - fun context(): Context? = context.getNullable("context") - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(): String? = id.getNullable("id") - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - fun datasetRecordId(): String? = datasetRecordId.getNullable("dataset_record_id") - - /** The timestamp the experiment event was created */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not show - * up in subsequent fetches for this experiment - */ - fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(): Boolean? = _isMerge.getNullable("_is_merge") - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot be - * specified alongside `_is_merge=true`. Tracking hierarchical relationships are important for - * tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent - * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after - * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row - * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this - * case, the `"llm_call"` row) by clicking on the "abc" row. - */ - fun _parentId(): String? = _parentId.getNullable("_parent_id") - - /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same between - * experiments, so they should not contain experiment-specific state. A simple rule of thumb is - * that if you run the same experiment twice, the `input` should be identical - */ - @JsonProperty("input") @ExcludeMissing fun _input() = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question - */ - @JsonProperty("output") @ExcludeMissing fun _output() = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate your experiments while - * digging into analyses. However, we may later use these values to re-score outputs or - * fine-tune your models - */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected - - /** The error that occurred, if any. */ - @JsonProperty("error") @ExcludeMissing fun _error() = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments - */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - @JsonProperty("metrics") @ExcludeMissing fun _metrics() = metrics - - /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event - */ - @JsonProperty("context") @ExcludeMissing fun _context() = context - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") @ExcludeMissing fun _spanAttributes() = spanAttributes - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - @JsonProperty("dataset_record_id") @ExcludeMissing fun _datasetRecordId() = datasetRecordId - - /** The timestamp the experiment event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not show - * up in subsequent fetches for this experiment - */ - @JsonProperty("_object_delete") @ExcludeMissing fun __objectDelete() = _objectDelete - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge() = _isMerge - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot be - * specified alongside `_is_merge=true`. Tracking hierarchical relationships are important for - * tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent - * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after - * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row - * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this - * case, the `"llm_call"` row) by clicking on the "abc" row. - */ - @JsonProperty("_parent_id") @ExcludeMissing fun __parentId() = _parentId - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InsertExperimentEventReplace = apply { - if (!validated) { - input() - output() - expected() - error() - scores()?.validate() - metadata()?.validate() - tags() - metrics()?.validate() - context()?.validate() - spanAttributes()?.validate() - id() - datasetRecordId() - created() - _objectDelete() - _isMerge() - _parentId() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InsertExperimentEventReplace && - this.input == other.input && - this.output == other.output && - this.expected == other.expected && - this.error == other.error && - this.scores == other.scores && - this.metadata == other.metadata && - this.tags == other.tags && - this.metrics == other.metrics && - this.context == other.context && - this.spanAttributes == other.spanAttributes && - this.id == other.id && - this.datasetRecordId == other.datasetRecordId && - this.created == other.created && - this._objectDelete == other._objectDelete && - this._isMerge == other._isMerge && - this._parentId == other._parentId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - input, - output, - expected, - error, - scores, - metadata, - tags, - metrics, - context, - spanAttributes, - id, - datasetRecordId, - created, - _objectDelete, - _isMerge, - _parentId, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InsertExperimentEventReplace{input=$input, output=$output, expected=$expected, error=$error, scores=$scores, metadata=$metadata, tags=$tags, metrics=$metrics, context=$context, spanAttributes=$spanAttributes, id=$id, datasetRecordId=$datasetRecordId, created=$created, _objectDelete=$_objectDelete, _isMerge=$_isMerge, _parentId=$_parentId, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var input: JsonValue = JsonMissing.of() - private var output: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() - private var error: JsonValue = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var metrics: JsonField = JsonMissing.of() - private var context: JsonField = JsonMissing.of() - private var spanAttributes: JsonField = JsonMissing.of() - private var id: JsonField = JsonMissing.of() - private var datasetRecordId: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var _objectDelete: JsonField = JsonMissing.of() - private var _isMerge: JsonField = JsonMissing.of() - private var _parentId: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(insertExperimentEventReplace: InsertExperimentEventReplace) = apply { - this.input = insertExperimentEventReplace.input - this.output = insertExperimentEventReplace.output - this.expected = insertExperimentEventReplace.expected - this.error = insertExperimentEventReplace.error - this.scores = insertExperimentEventReplace.scores - this.metadata = insertExperimentEventReplace.metadata - this.tags = insertExperimentEventReplace.tags - this.metrics = insertExperimentEventReplace.metrics - this.context = insertExperimentEventReplace.context - this.spanAttributes = insertExperimentEventReplace.spanAttributes - this.id = insertExperimentEventReplace.id - this.datasetRecordId = insertExperimentEventReplace.datasetRecordId - this.created = insertExperimentEventReplace.created - this._objectDelete = insertExperimentEventReplace._objectDelete - this._isMerge = insertExperimentEventReplace._isMerge - this._parentId = insertExperimentEventReplace._parentId - additionalProperties(insertExperimentEventReplace.additionalProperties) - } - - /** - * The arguments that uniquely define a test case (an arbitrary, JSON serializable object). - * Later on, Braintrust will use the `input` to know whether two test cases are the same - * between experiments, so they should not contain experiment-specific state. A simple rule - * of thumb is that if you run the same experiment twice, the `input` should be identical - */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } - - /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object), that allows you to determine whether the result is correct or not. - * For example, in an app that generates SQL queries, the `output` should be the _result_ of - * the SQL query generated by the model, not the query itself, because there may be multiple - * valid queries that answer a single question - */ - @JsonProperty("output") - @ExcludeMissing - fun output(output: JsonValue) = apply { this.output = output } - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does - * not compare `output` to `expected` for you, since there are so many different ways to do - * that correctly. Instead, these values are just used to help you navigate your experiments - * while digging into analyses. However, we may later use these values to re-score outputs - * or fine-tune your models - */ - @JsonProperty("expected") - @ExcludeMissing - fun expected(expected: JsonValue) = apply { this.expected = expected } - - /** The error that occurred, if any. */ - @JsonProperty("error") - @ExcludeMissing - fun error(error: JsonValue) = apply { this.error = error } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare experiments - */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare experiments - */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - fun metrics(metrics: Metrics) = metrics(JsonField.of(metrics)) - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - @JsonProperty("metrics") - @ExcludeMissing - fun metrics(metrics: JsonField) = apply { this.metrics = metrics } - - /** - * Context is additional information about the code that produced the experiment event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the experiment event - */ - fun context(context: Context) = context(JsonField.of(context)) - - /** - * Context is additional information about the code that produced the experiment event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the experiment event - */ - @JsonProperty("context") - @ExcludeMissing - fun context(context: JsonField) = apply { this.context = context } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(spanAttributes: SpanAttributes) = - spanAttributes(JsonField.of(spanAttributes)) - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") - @ExcludeMissing - fun spanAttributes(spanAttributes: JsonField) = apply { - this.spanAttributes = spanAttributes - } - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(id: String) = id(JsonField.of(id)) - - /** - * A unique identifier for the experiment event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - fun datasetRecordId(datasetRecordId: String) = - datasetRecordId(JsonField.of(datasetRecordId)) - - /** - * If the experiment is associated to a dataset, this is the event-level dataset id this - * experiment event is tied to - */ - @JsonProperty("dataset_record_id") - @ExcludeMissing - fun datasetRecordId(datasetRecordId: JsonField) = apply { - this.datasetRecordId = datasetRecordId - } - - /** The timestamp the experiment event was created */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** The timestamp the experiment event was created */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not - * show up in subsequent fetches for this experiment - */ - fun _objectDelete(_objectDelete: Boolean) = _objectDelete(JsonField.of(_objectDelete)) - - /** - * Pass `_object_delete=true` to mark the experiment event deleted. Deleted events will not - * show up in subsequent fetches for this experiment - */ - @JsonProperty("_object_delete") - @ExcludeMissing - fun _objectDelete(_objectDelete: JsonField) = apply { - this._objectDelete = _objectDelete - } - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(_isMerge: Boolean) = _isMerge(JsonField.of(_isMerge)) - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") - @ExcludeMissing - fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot - * be specified alongside `_is_merge=true`. Tracking hierarchical relationships are - * important for tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) - * for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the - * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What - * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the - * root span row `"abc"` will show up in the summary view. You can view the full trace - * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. - */ - fun _parentId(_parentId: String) = _parentId(JsonField.of(_parentId)) - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot - * be specified alongside `_is_merge=true`. Tracking hierarchical relationships are - * important for tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) - * for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the - * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What - * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the - * root span row `"abc"` will show up in the summary view. You can view the full trace - * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. - */ - @JsonProperty("_parent_id") - @ExcludeMissing - fun _parentId(_parentId: JsonField) = apply { this._parentId = _parentId } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): InsertExperimentEventReplace = - InsertExperimentEventReplace( - input, - output, - expected, - error, - scores, - metadata, - tags.map { it.toUnmodifiable() }, - metrics, - context, - spanAttributes, - id, - datasetRecordId, - created, - _objectDelete, - _isMerge, - _parentId, - additionalProperties.toUnmodifiable(), - ) - } - - /** - * Context is additional information about the code that produced the experiment event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the experiment event - */ - @JsonDeserialize(builder = Context.Builder::class) - @NoAutoDetect - class Context - private constructor( - private val callerFunctionname: JsonField, - private val callerFilename: JsonField, - private val callerLineno: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The function in code which created the experiment event */ - fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") - - /** Name of the file in code where the experiment event was created */ - fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - - /** Line of code where the experiment event was created */ - fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") - - /** The function in code which created the experiment event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun _callerFunctionname() = callerFunctionname - - /** Name of the file in code where the experiment event was created */ - @JsonProperty("caller_filename") @ExcludeMissing fun _callerFilename() = callerFilename - - /** Line of code where the experiment event was created */ - @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno() = callerLineno - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Context = apply { - if (!validated) { - callerFunctionname() - callerFilename() - callerLineno() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Context && - this.callerFunctionname == other.callerFunctionname && - this.callerFilename == other.callerFilename && - this.callerLineno == other.callerLineno && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Context{callerFunctionname=$callerFunctionname, callerFilename=$callerFilename, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var callerFunctionname: JsonField = JsonMissing.of() - private var callerFilename: JsonField = JsonMissing.of() - private var callerLineno: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(context: Context) = apply { - this.callerFunctionname = context.callerFunctionname - this.callerFilename = context.callerFilename - this.callerLineno = context.callerLineno - additionalProperties(context.additionalProperties) - } - - /** The function in code which created the experiment event */ - fun callerFunctionname(callerFunctionname: String) = - callerFunctionname(JsonField.of(callerFunctionname)) - - /** The function in code which created the experiment event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun callerFunctionname(callerFunctionname: JsonField) = apply { - this.callerFunctionname = callerFunctionname - } - - /** Name of the file in code where the experiment event was created */ - fun callerFilename(callerFilename: String) = - callerFilename(JsonField.of(callerFilename)) - - /** Name of the file in code where the experiment event was created */ - @JsonProperty("caller_filename") - @ExcludeMissing - fun callerFilename(callerFilename: JsonField) = apply { - this.callerFilename = callerFilename - } - - /** Line of code where the experiment event was created */ - fun callerLineno(callerLineno: Long) = callerLineno(JsonField.of(callerLineno)) - - /** Line of code where the experiment event was created */ - @JsonProperty("caller_lineno") - @ExcludeMissing - fun callerLineno(callerLineno: JsonField) = apply { - this.callerLineno = callerLineno - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Context = - Context( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * experiment event. Use "start" and "end" to track the time span over which the experiment - * event was produced - */ - @JsonDeserialize(builder = Metrics.Builder::class) - @NoAutoDetect - class Metrics - private constructor( - private val start: JsonField, - private val end: JsonField, - private val promptTokens: JsonField, - private val completionTokens: JsonField, - private val tokens: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * started - */ - fun start(): Double? = start.getNullable("start") - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * finished - */ - fun end(): Double? = end.getNullable("end") - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") - - /** The total number of tokens in the input and output of the experiment event. */ - fun tokens(): Long? = tokens.getNullable("tokens") - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * started - */ - @JsonProperty("start") @ExcludeMissing fun _start() = start - - /** - * A unix timestamp recording when the section of code which produced the experiment event - * finished - */ - @JsonProperty("end") @ExcludeMissing fun _end() = end - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - @JsonProperty("prompt_tokens") @ExcludeMissing fun _promptTokens() = promptTokens - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun _completionTokens() = completionTokens - - /** The total number of tokens in the input and output of the experiment event. */ - @JsonProperty("tokens") @ExcludeMissing fun _tokens() = tokens - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metrics = apply { - if (!validated) { - start() - end() - promptTokens() - completionTokens() - tokens() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metrics && - this.start == other.start && - this.end == other.end && - this.promptTokens == other.promptTokens && - this.completionTokens == other.completionTokens && - this.tokens == other.tokens && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Metrics{start=$start, end=$end, promptTokens=$promptTokens, completionTokens=$completionTokens, tokens=$tokens, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var start: JsonField = JsonMissing.of() - private var end: JsonField = JsonMissing.of() - private var promptTokens: JsonField = JsonMissing.of() - private var completionTokens: JsonField = JsonMissing.of() - private var tokens: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metrics: Metrics) = apply { - this.start = metrics.start - this.end = metrics.end - this.promptTokens = metrics.promptTokens - this.completionTokens = metrics.completionTokens - this.tokens = metrics.tokens - additionalProperties(metrics.additionalProperties) - } - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event started - */ - fun start(start: Double) = start(JsonField.of(start)) - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event started - */ - @JsonProperty("start") - @ExcludeMissing - fun start(start: JsonField) = apply { this.start = start } - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event finished - */ - fun end(end: Double) = end(JsonField.of(end)) - - /** - * A unix timestamp recording when the section of code which produced the experiment - * event finished - */ - @JsonProperty("end") - @ExcludeMissing - fun end(end: JsonField) = apply { this.end = end } - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - fun promptTokens(promptTokens: Long) = promptTokens(JsonField.of(promptTokens)) - - /** - * The number of tokens in the prompt used to generate the experiment event (only set if - * this is an LLM span) - */ - @JsonProperty("prompt_tokens") - @ExcludeMissing - fun promptTokens(promptTokens: JsonField) = apply { - this.promptTokens = promptTokens - } - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - fun completionTokens(completionTokens: Long) = - completionTokens(JsonField.of(completionTokens)) - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun completionTokens(completionTokens: JsonField) = apply { - this.completionTokens = completionTokens - } - - /** The total number of tokens in the input and output of the experiment event. */ - fun tokens(tokens: Long) = tokens(JsonField.of(tokens)) - - /** The total number of tokens in the input and output of the experiment event. */ - @JsonProperty("tokens") - @ExcludeMissing - fun tokens(tokens: JsonField) = apply { this.tokens = tokens } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metrics = - Metrics( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare experiments - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Scores = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Scores && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Scores{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) - } - } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonDeserialize(builder = SpanAttributes.Builder::class) - @NoAutoDetect - class SpanAttributes - private constructor( - private val name: JsonField, - private val type: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Name of the span, for display purposes only */ - fun name(): String? = name.getNullable("name") - - /** Type of the span, for display purposes only */ - fun type(): Type? = type.getNullable("type") - - /** Name of the span, for display purposes only */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Type of the span, for display purposes only */ - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): SpanAttributes = apply { - if (!validated) { - name() - type() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SpanAttributes && - this.name == other.name && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SpanAttributes{name=$name, type=$type, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var name: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(spanAttributes: SpanAttributes) = apply { - this.name = spanAttributes.name - this.type = spanAttributes.type - additionalProperties(spanAttributes.additionalProperties) - } - - /** Name of the span, for display purposes only */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the span, for display purposes only */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - /** Type of the span, for display purposes only */ - fun type(type: Type) = type(JsonField.of(type)) - - /** Type of the span, for display purposes only */ - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): SpanAttributes = - SpanAttributes( - name, - type, - additionalProperties.toUnmodifiable(), - ) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val LLM = Type(JsonField.of("llm")) - - val SCORE = Type(JsonField.of("score")) - - val FUNCTION = Type(JsonField.of("function")) - - val EVAL = Type(JsonField.of("eval")) - - val TASK = Type(JsonField.of("task")) - - val TOOL = Type(JsonField.of("tool")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - } - - enum class Value { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - LLM -> Value.LLM - SCORE -> Value.SCORE - FUNCTION -> Value.FUNCTION - EVAL -> Value.EVAL - TASK -> Value.TASK - TOOL -> Value.TOOL - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - LLM -> Known.LLM - SCORE -> Known.SCORE - FUNCTION -> Known.FUNCTION - EVAL -> Known.EVAL - TASK -> Known.TASK - TOOL -> Known.TOOL - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEvent.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEvent.kt new file mode 100644 index 00000000..943c0899 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEvent.kt @@ -0,0 +1,2026 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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.util.Collections +import java.util.Objects + +/** A project logs event */ +class InsertProjectLogsEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val _isMerge: JsonField, + private val _mergePaths: JsonField>>, + private val _objectDelete: JsonField, + private val _parentId: JsonField, + private val context: JsonField, + private val created: JsonField, + private val error: JsonValue, + private val expected: JsonValue, + private val input: JsonValue, + private val metadata: JsonField, + private val metrics: JsonField, + private val origin: JsonField, + private val output: JsonValue, + private val rootSpanId: JsonField, + private val scores: JsonField, + private val spanAttributes: JsonField, + private val spanId: JsonField, + private val spanParents: JsonField>, + private val tags: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_is_merge") @ExcludeMissing _isMerge: JsonField = JsonMissing.of(), + @JsonProperty("_merge_paths") + @ExcludeMissing + _mergePaths: JsonField>> = JsonMissing.of(), + @JsonProperty("_object_delete") + @ExcludeMissing + _objectDelete: JsonField = JsonMissing.of(), + @JsonProperty("_parent_id") @ExcludeMissing _parentId: JsonField = JsonMissing.of(), + @JsonProperty("context") @ExcludeMissing context: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonValue = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonValue = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("metrics") @ExcludeMissing metrics: JsonField = JsonMissing.of(), + @JsonProperty("origin") + @ExcludeMissing + origin: JsonField = JsonMissing.of(), + @JsonProperty("output") @ExcludeMissing output: JsonValue = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + @JsonProperty("span_attributes") + @ExcludeMissing + spanAttributes: JsonField = JsonMissing.of(), + @JsonProperty("span_id") @ExcludeMissing spanId: JsonField = JsonMissing.of(), + @JsonProperty("span_parents") + @ExcludeMissing + spanParents: JsonField> = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _isMerge, + _mergePaths, + _objectDelete, + _parentId, + context, + created, + error, + expected, + input, + metadata, + metrics, + origin, + output, + rootSpanId, + scores, + spanAttributes, + spanId, + spanParents, + tags, + mutableMapOf(), + ) + + /** + * A unique identifier for the project logs event. If you don't provide one, BrainTrust will + * generate one for you + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun id(): String? = id.getNullable("id") + + /** + * The `_is_merge` field controls how the row is merged with any existing row with the same id + * in the DB. By default (or when set to `false`), the existing row is completely replaced by + * the new row. When set to `true`, the new row is deep-merged into the existing row, if one is + * found. If no existing row is found, the new row is inserted as is. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": + * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": + * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we + * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be + * `{"id": "foo", "input": {"b": 11, "c": 20}}` + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _isMerge(): Boolean? = _isMerge.getNullable("_is_merge") + + /** + * The `_merge_paths` field allows controlling the depth of the merge, when `_is_merge=true`. + * `_merge_paths` is a list of paths, where each path is a list of field names. The deep merge + * will not descend below any of the specified merge paths. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, + * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, + * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, + * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": + * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the + * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and + * `input.c`. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _mergePaths(): List>? = _mergePaths.getNullable("_merge_paths") + + /** + * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will not + * show up in subsequent fetches for this project logs + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") + + /** + * DEPRECATED: The `_parent_id` field is deprecated and should not be used. Support for + * `_parent_id` will be dropped in a future version of Braintrust. Log `span_id`, + * `root_span_id`, and `span_parents` explicitly instead. + * + * Use the `_parent_id` field to create this row as a subspan of an existing row. Tracking + * hierarchical relationships are important for tracing (see the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). + * + * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", + * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent + * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after + * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row + * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this + * case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _parentId(): String? = _parentId.getNullable("_parent_id") + + /** + * Context is additional information about the code that produced the project logs event. It is + * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the + * location in code which produced the project logs event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun context(): Context? = context.getNullable("context") + + /** + * The timestamp the project logs event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") + + /** The error that occurred, if any. */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonValue = error + + /** + * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to + * `output` to determine if your `output` value is correct or not. Braintrust currently does not + * compare `output` to `expected` for you, since there are so many different ways to do that + * correctly. Instead, these values are just used to help you navigate while digging into + * analyses. However, we may later use these values to re-score outputs or fine-tune your + * models. + */ + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected + + /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonValue = input + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. For + * example, you could log the `prompt`, example's `id`, or anything else that would be useful to + * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys + * must be strings + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metadata(): Metadata? = metadata.getNullable("metadata") + + /** + * Metrics are numerical measurements tracking the execution of the code that produced the + * project logs event. Use "start" and "end" to track the time span over which the project logs + * event was produced + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun metrics(): Metrics? = metrics.getNullable("metrics") + + /** + * Indicates the event was copied from another object. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun origin(): ObjectReference? = origin.getNullable("origin") + + /** + * The output of your application, including post-processing (an arbitrary, JSON serializable + * object), that allows you to determine whether the result is correct or not. For example, in + * an app that generates SQL queries, the `output` should be the _result_ of the SQL query + * generated by the model, not the query itself, because there may be multiple valid queries + * that answer a single question. + */ + @JsonProperty("output") @ExcludeMissing fun _output(): JsonValue = output + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun rootSpanId(): String? = rootSpanId.getNullable("root_span_id") + + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare logs. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun scores(): Scores? = scores.getNullable("scores") + + /** + * Human-identifying attributes of the span, such as name, type, etc. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanId(): String? = spanId.getNullable("span_id") + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, and + * the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": {"correctness": + * 0.33}}`. We can create a sub-span of the parent row by logging `{"id": "llm_call", "span_id": + * "span1", "root_span_id": "root_span0", "span_parents": ["span0"], "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root + * span row `"abc"` will show up in the summary view. You can view the full trace hierarchy (in + * this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanParents(): List? = spanParents.getNullable("span_parents") + + /** + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") + + /** + * 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 [_isMerge]. + * + * Unlike [_isMerge], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge(): JsonField = _isMerge + + /** + * Returns the raw JSON value of [_mergePaths]. + * + * Unlike [_mergePaths], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_merge_paths") + @ExcludeMissing + fun __mergePaths(): JsonField>> = _mergePaths + + /** + * Returns the raw JSON value of [_objectDelete]. + * + * Unlike [_objectDelete], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_object_delete") + @ExcludeMissing + fun __objectDelete(): JsonField = _objectDelete + + /** + * Returns the raw JSON value of [_parentId]. + * + * Unlike [_parentId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_parent_id") @ExcludeMissing fun __parentId(): JsonField = _parentId + + /** + * 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 [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * 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 [metrics]. + * + * Unlike [metrics], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metrics") @ExcludeMissing fun _metrics(): JsonField = metrics + + /** + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin + + /** + * Returns the raw JSON value of [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId(): JsonField = rootSpanId + + /** + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores + + /** + * Returns the raw JSON value of [spanAttributes]. + * + * Unlike [spanAttributes], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_attributes") + @ExcludeMissing + fun _spanAttributes(): JsonField = spanAttributes + + /** + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId + + /** + * Returns the raw JSON value of [spanParents]. + * + * Unlike [spanParents], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("span_parents") + @ExcludeMissing + fun _spanParents(): JsonField> = spanParents + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags + + @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 [InsertProjectLogsEvent]. */ + fun builder() = Builder() + } + + /** A builder for [InsertProjectLogsEvent]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var _isMerge: JsonField = JsonMissing.of() + private var _mergePaths: JsonField>>? = null + private var _objectDelete: JsonField = JsonMissing.of() + private var _parentId: JsonField = JsonMissing.of() + private var context: JsonField = JsonMissing.of() + private var created: JsonField = JsonMissing.of() + private var error: JsonValue = JsonMissing.of() + private var expected: JsonValue = JsonMissing.of() + private var input: JsonValue = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var metrics: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var output: JsonValue = JsonMissing.of() + private var rootSpanId: JsonField = JsonMissing.of() + private var scores: JsonField = JsonMissing.of() + private var spanAttributes: JsonField = JsonMissing.of() + private var spanId: JsonField = JsonMissing.of() + private var spanParents: JsonField>? = null + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(insertProjectLogsEvent: InsertProjectLogsEvent) = apply { + id = insertProjectLogsEvent.id + _isMerge = insertProjectLogsEvent._isMerge + _mergePaths = insertProjectLogsEvent._mergePaths.map { it.toMutableList() } + _objectDelete = insertProjectLogsEvent._objectDelete + _parentId = insertProjectLogsEvent._parentId + context = insertProjectLogsEvent.context + created = insertProjectLogsEvent.created + error = insertProjectLogsEvent.error + expected = insertProjectLogsEvent.expected + input = insertProjectLogsEvent.input + metadata = insertProjectLogsEvent.metadata + metrics = insertProjectLogsEvent.metrics + origin = insertProjectLogsEvent.origin + output = insertProjectLogsEvent.output + rootSpanId = insertProjectLogsEvent.rootSpanId + scores = insertProjectLogsEvent.scores + spanAttributes = insertProjectLogsEvent.spanAttributes + spanId = insertProjectLogsEvent.spanId + spanParents = insertProjectLogsEvent.spanParents.map { it.toMutableList() } + tags = insertProjectLogsEvent.tags.map { it.toMutableList() } + additionalProperties = insertProjectLogsEvent.additionalProperties.toMutableMap() + } + + /** + * A unique identifier for the project logs event. If you don't provide one, BrainTrust will + * generate one for you + */ + fun id(id: String?) = id(JsonField.ofNullable(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 } + + /** + * The `_is_merge` field controls how the row is merged with any existing row with the same + * id in the DB. By default (or when set to `false`), the existing row is completely + * replaced by the new row. When set to `true`, the new row is deep-merged into the existing + * row, if one is found. If no existing row is found, the new row is inserted as is. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": + * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": + * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we + * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be + * `{"id": "foo", "input": {"b": 11, "c": 20}}` + */ + fun _isMerge(_isMerge: Boolean?) = _isMerge(JsonField.ofNullable(_isMerge)) + + /** + * Alias for [Builder._isMerge]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun _isMerge(_isMerge: Boolean) = _isMerge(_isMerge as Boolean?) + + /** + * Sets [Builder._isMerge] to an arbitrary JSON value. + * + * You should usually call [Builder._isMerge] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } + + /** + * The `_merge_paths` field allows controlling the depth of the merge, when + * `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of field + * names. The deep merge will not descend below any of the specified merge paths. + * + * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": + * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": + * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": + * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": + * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this + * case, due to the merge paths, we have replaced `input.a` and `output`, but have still + * deep-merged `input` and `input.c`. + */ + fun _mergePaths(_mergePaths: List>?) = + _mergePaths(JsonField.ofNullable(_mergePaths)) + + /** + * Sets [Builder._mergePaths] to an arbitrary JSON value. + * + * You should usually call [Builder._mergePaths] with a well-typed `List>` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun _mergePaths(_mergePaths: JsonField>>) = apply { + this._mergePaths = _mergePaths.map { it.toMutableList() } + } + + /** + * Adds a single [List] to [_mergePaths]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMergePath(mergePath: List) = apply { + _mergePaths = + (_mergePaths ?: JsonField.of(mutableListOf())).also { + checkKnown("_mergePaths", it).add(mergePath) + } + } + + /** + * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will + * not show up in subsequent fetches for this project logs + */ + fun _objectDelete(_objectDelete: Boolean?) = + _objectDelete(JsonField.ofNullable(_objectDelete)) + + /** + * Alias for [Builder._objectDelete]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun _objectDelete(_objectDelete: Boolean) = _objectDelete(_objectDelete as Boolean?) + + /** + * Sets [Builder._objectDelete] to an arbitrary JSON value. + * + * You should usually call [Builder._objectDelete] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun _objectDelete(_objectDelete: JsonField) = apply { + this._objectDelete = _objectDelete + } + + /** + * DEPRECATED: The `_parent_id` field is deprecated and should not be used. Support for + * `_parent_id` will be dropped in a future version of Braintrust. Log `span_id`, + * `root_span_id`, and `span_parents` explicitly instead. + * + * Use the `_parent_id` field to create this row as a subspan of an existing row. Tracking + * hierarchical relationships are important for tracing (see the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). + * + * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", + * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the + * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What + * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the + * root span row `"abc"` will show up in the summary view. You can view the full trace + * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun _parentId(_parentId: String?) = _parentId(JsonField.ofNullable(_parentId)) + + /** + * Sets [Builder._parentId] to an arbitrary JSON value. + * + * You should usually call [Builder._parentId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _parentId(_parentId: JsonField) = apply { this._parentId = _parentId } + + /** + * Context is additional information about the code that produced the project logs event. It + * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to + * track the location in code which produced the project logs event + */ + fun context(context: Context?) = context(JsonField.ofNullable(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 } + + /** The timestamp the project logs event was created */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } + + /** The error that occurred, if any. */ + fun error(error: JsonValue) = apply { this.error = error } + + /** + * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to + * `output` to determine if your `output` value is correct or not. Braintrust currently does + * not compare `output` to `expected` for you, since there are so many different ways to do + * that correctly. Instead, these values are just used to help you navigate while digging + * into analyses. However, we may later use these values to re-score outputs or fine-tune + * your models. + */ + fun expected(expected: JsonValue) = apply { this.expected = expected } + + /** + * The arguments that uniquely define a user input (an arbitrary, JSON serializable object). + */ + fun input(input: JsonValue) = apply { this.input = input } + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. + * For example, you could log the `prompt`, example's `id`, or anything else that would be + * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, + * but its keys must be strings + */ + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(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 } + + /** + * Metrics are numerical measurements tracking the execution of the code that produced the + * project logs event. Use "start" and "end" to track the time span over which the project + * logs event was produced + */ + fun metrics(metrics: Metrics?) = metrics(JsonField.ofNullable(metrics)) + + /** + * Sets [Builder.metrics] to an arbitrary JSON value. + * + * You should usually call [Builder.metrics] with a well-typed [Metrics] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun metrics(metrics: JsonField) = apply { this.metrics = metrics } + + /** Indicates the event was copied from another object. */ + fun origin(origin: ObjectReference?) = origin(JsonField.ofNullable(origin)) + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [ObjectReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun origin(origin: JsonField) = apply { this.origin = origin } + + /** + * The output of your application, including post-processing (an arbitrary, JSON + * serializable object), that allows you to determine whether the result is correct or not. + * For example, in an app that generates SQL queries, the `output` should be the _result_ of + * the SQL query generated by the model, not the query itself, because there may be multiple + * valid queries that answer a single question. + */ + fun output(output: JsonValue) = apply { this.output = output } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun rootSpanId(rootSpanId: String?) = rootSpanId(JsonField.ofNullable(rootSpanId)) + + /** + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a + * variety of signals that help you determine how accurate the outputs are compared to what + * you expect and diagnose failures. For example, a summarization app might have one score + * that tells you how accurate the summary is, and another that measures the word similarity + * between the generated and grouth truth summary. The word similarity score could help you + * determine whether the summarization was covering similar concepts or not. You can use + * these scores to help you sort, filter, and compare logs. + */ + fun scores(scores: Scores?) = scores(JsonField.ofNullable(scores)) + + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun scores(scores: JsonField) = apply { this.scores = scores } + + /** Human-identifying attributes of the span, such as name, type, etc. */ + fun spanAttributes(spanAttributes: SpanAttributes?) = + spanAttributes(JsonField.ofNullable(spanAttributes)) + + /** + * Sets [Builder.spanAttributes] to an arbitrary JSON value. + * + * You should usually call [Builder.spanAttributes] with a well-typed [SpanAttributes] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun spanAttributes(spanAttributes: JsonField) = apply { + this.spanAttributes = spanAttributes + } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun spanId(spanId: String?) = spanId(JsonField.ofNullable(spanId)) + + /** + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } + + /** + * Use `span_id`, `root_span_id`, and `span_parents` instead of `_parent_id`, which is now + * deprecated. The span_id is a unique identifier describing the row's place in the a trace, + * and the root_span_id is a unique identifier for the whole trace. See the + * [guide](https://www.braintrust.dev/docs/guides/tracing) for full details. + * + * For example, say we have logged a row `{"id": "abc", "span_id": "span0", "root_span_id": + * "root_span0", "input": "foo", "output": "bar", "expected": "boo", "scores": + * {"correctness": 0.33}}`. We can create a sub-span of the parent row by logging `{"id": + * "llm_call", "span_id": "span1", "root_span_id": "root_span0", "span_parents": ["span0"], + * "input": {"prompt": "What comes after foo?"}, "output": "bar", "metrics": {"tokens": + * 1}}`. In the webapp, only the root span row `"abc"` will show up in the summary view. You + * can view the full trace hierarchy (in this case, the `"llm_call"` row) by clicking on the + * "abc" row. + * + * If the row is being merged into an existing row, this field will be ignored. + */ + fun spanParents(spanParents: List?) = spanParents(JsonField.ofNullable(spanParents)) + + /** + * Sets [Builder.spanParents] to an arbitrary JSON value. + * + * You should usually call [Builder.spanParents] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun spanParents(spanParents: JsonField>) = apply { + this.spanParents = spanParents.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [spanParents]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSpanParent(spanParent: String) = apply { + spanParents = + (spanParents ?: JsonField.of(mutableListOf())).also { + checkKnown("spanParents", it).add(spanParent) + } + } + + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } + + 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 [InsertProjectLogsEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): InsertProjectLogsEvent = + InsertProjectLogsEvent( + id, + _isMerge, + (_mergePaths ?: JsonMissing.of()).map { it.toImmutable() }, + _objectDelete, + _parentId, + context, + created, + error, + expected, + input, + metadata, + metrics, + origin, + output, + rootSpanId, + scores, + spanAttributes, + spanId, + (spanParents ?: JsonMissing.of()).map { it.toImmutable() }, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): InsertProjectLogsEvent = apply { + if (validated) { + return@apply + } + + id() + _isMerge() + _mergePaths() + _objectDelete() + _parentId() + context()?.validate() + created() + metadata()?.validate() + metrics()?.validate() + origin()?.validate() + rootSpanId() + scores()?.validate() + spanAttributes()?.validate() + spanId() + spanParents() + tags() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_isMerge.asKnown() == null) 0 else 1) + + (_mergePaths.asKnown()?.sumOf { it.size.toInt() } ?: 0) + + (if (_objectDelete.asKnown() == null) 0 else 1) + + (if (_parentId.asKnown() == null) 0 else 1) + + (context.asKnown()?.validity() ?: 0) + + (if (created.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (metrics.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (scores.asKnown()?.validity() ?: 0) + + (spanAttributes.asKnown()?.validity() ?: 0) + + (if (spanId.asKnown() == null) 0 else 1) + + (spanParents.asKnown()?.size ?: 0) + + (tags.asKnown()?.size ?: 0) + + /** + * Context is additional information about the code that produced the project logs event. It is + * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the + * location in code which produced the project logs event + */ + class Context + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val callerFilename: JsonField, + private val callerFunctionname: JsonField, + private val callerLineno: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonField = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonField = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonField = JsonMissing.of(), + ) : this(callerFilename, callerFunctionname, callerLineno, mutableMapOf()) + + /** + * Name of the file in code where the project logs event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerFilename(): String? = callerFilename.getNullable("caller_filename") + + /** + * The function in code which created the project logs event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") + + /** + * Line of code where the project logs event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") + + /** + * Returns the raw JSON value of [callerFilename]. + * + * Unlike [callerFilename], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonField = callerFilename + + /** + * Returns the raw JSON value of [callerFunctionname]. + * + * Unlike [callerFunctionname], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("caller_functionname") + @ExcludeMissing + fun _callerFunctionname(): JsonField = callerFunctionname + + /** + * Returns the raw JSON value of [callerLineno]. + * + * Unlike [callerLineno], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_lineno") + @ExcludeMissing + fun _callerLineno(): JsonField = callerLineno + + @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]. */ + fun builder() = Builder() + } + + /** A builder for [Context]. */ + class Builder internal constructor() { + + private var callerFilename: JsonField = JsonMissing.of() + private var callerFunctionname: JsonField = JsonMissing.of() + private var callerLineno: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(context: Context) = apply { + callerFilename = context.callerFilename + callerFunctionname = context.callerFunctionname + callerLineno = context.callerLineno + additionalProperties = context.additionalProperties.toMutableMap() + } + + /** Name of the file in code where the project logs event was created */ + fun callerFilename(callerFilename: String?) = + callerFilename(JsonField.ofNullable(callerFilename)) + + /** + * Sets [Builder.callerFilename] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFilename] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerFilename(callerFilename: JsonField) = apply { + this.callerFilename = callerFilename + } + + /** The function in code which created the project logs event */ + fun callerFunctionname(callerFunctionname: String?) = + callerFunctionname(JsonField.ofNullable(callerFunctionname)) + + /** + * Sets [Builder.callerFunctionname] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFunctionname] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerFunctionname(callerFunctionname: JsonField) = apply { + this.callerFunctionname = callerFunctionname + } + + /** Line of code where the project logs event was created */ + fun callerLineno(callerLineno: Long?) = callerLineno(JsonField.ofNullable(callerLineno)) + + /** + * Alias for [Builder.callerLineno]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun callerLineno(callerLineno: Long) = callerLineno(callerLineno as Long?) + + /** + * Sets [Builder.callerLineno] to an arbitrary JSON value. + * + * You should usually call [Builder.callerLineno] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerLineno(callerLineno: JsonField) = apply { + this.callerLineno = callerLineno + } + + 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. + */ + fun build(): Context = + Context( + callerFilename, + callerFunctionname, + callerLineno, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Context = apply { + if (validated) { + return@apply + } + + callerFilename() + callerFunctionname() + callerLineno() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (callerFilename.asKnown() == null) 0 else 1) + + (if (callerFunctionname.asKnown() == null) 0 else 1) + + (if (callerLineno.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Context && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(callerFilename, callerFunctionname, callerLineno, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Context{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" + } + + /** + * A dictionary with additional data about the test example, model outputs, or just about + * anything else that's relevant, that you can use to help find and analyze examples later. For + * example, you could log the `prompt`, example's `id`, or anything else that would be useful to + * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys + * must be strings + */ + class Metadata + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of() + ) : this(model, mutableMapOf()) + + /** + * The model used for this example + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): String? = model.getNullable("model") + + /** + * 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 + + @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 [Metadata]. */ + fun builder() = Builder() + } + + /** A builder for [Metadata]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(metadata: Metadata) = apply { + model = metadata.model + additionalProperties = metadata.additionalProperties.toMutableMap() + } + + /** The model used for this example */ + fun model(model: String?) = model(JsonField.ofNullable(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 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(model, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + model() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (model.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && + model == other.model && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(model, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metadata{model=$model, additionalProperties=$additionalProperties}" + } + + /** + * Metrics are numerical measurements tracking the execution of the code that produced the + * project logs event. Use "start" and "end" to track the time span over which the project logs + * event was produced + */ + class Metrics + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val callerFilename: JsonValue, + private val callerFunctionname: JsonValue, + private val callerLineno: JsonValue, + private val completionTokens: JsonField, + private val end: JsonField, + private val promptTokens: JsonField, + private val start: JsonField, + private val tokens: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonValue = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonValue = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonValue = JsonMissing.of(), + @JsonProperty("completion_tokens") + @ExcludeMissing + completionTokens: JsonField = JsonMissing.of(), + @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), + @JsonProperty("prompt_tokens") + @ExcludeMissing + promptTokens: JsonField = JsonMissing.of(), + @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), + @JsonProperty("tokens") @ExcludeMissing tokens: JsonField = JsonMissing.of(), + ) : this( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + mutableMapOf(), + ) + + /** This metric is deprecated */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonValue = callerFilename + + /** This metric is deprecated */ + @JsonProperty("caller_functionname") + @ExcludeMissing + fun _callerFunctionname(): JsonValue = callerFunctionname + + /** This metric is deprecated */ + @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno(): JsonValue = callerLineno + + /** + * The number of tokens in the completion generated by the model (only set if this is an LLM + * span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") + + /** + * A unix timestamp recording when the section of code which produced the project logs event + * finished + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun end(): Double? = end.getNullable("end") + + /** + * The number of tokens in the prompt used to generate the project logs event (only set if + * this is an LLM span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") + + /** + * A unix timestamp recording when the section of code which produced the project logs event + * started + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun start(): Double? = start.getNullable("start") + + /** + * The total number of tokens in the input and output of the project logs event. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tokens(): Long? = tokens.getNullable("tokens") + + /** + * Returns the raw JSON value of [completionTokens]. + * + * Unlike [completionTokens], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("completion_tokens") + @ExcludeMissing + fun _completionTokens(): JsonField = completionTokens + + /** + * Returns the raw JSON value of [end]. + * + * Unlike [end], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end + + /** + * Returns the raw JSON value of [promptTokens]. + * + * Unlike [promptTokens], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("prompt_tokens") + @ExcludeMissing + fun _promptTokens(): JsonField = promptTokens + + /** + * Returns the raw JSON value of [start]. + * + * Unlike [start], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start + + /** + * Returns the raw JSON value of [tokens]. + * + * Unlike [tokens], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tokens") @ExcludeMissing fun _tokens(): JsonField = tokens + + @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 [Metrics]. */ + fun builder() = Builder() + } + + /** A builder for [Metrics]. */ + class Builder internal constructor() { + + private var callerFilename: JsonValue = JsonMissing.of() + private var callerFunctionname: JsonValue = JsonMissing.of() + private var callerLineno: JsonValue = JsonMissing.of() + private var completionTokens: JsonField = JsonMissing.of() + private var end: JsonField = JsonMissing.of() + private var promptTokens: JsonField = JsonMissing.of() + private var start: JsonField = JsonMissing.of() + private var tokens: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(metrics: Metrics) = apply { + callerFilename = metrics.callerFilename + callerFunctionname = metrics.callerFunctionname + callerLineno = metrics.callerLineno + completionTokens = metrics.completionTokens + end = metrics.end + promptTokens = metrics.promptTokens + start = metrics.start + tokens = metrics.tokens + additionalProperties = metrics.additionalProperties.toMutableMap() + } + + /** This metric is deprecated */ + fun callerFilename(callerFilename: JsonValue) = apply { + this.callerFilename = callerFilename + } + + /** This metric is deprecated */ + fun callerFunctionname(callerFunctionname: JsonValue) = apply { + this.callerFunctionname = callerFunctionname + } + + /** This metric is deprecated */ + fun callerLineno(callerLineno: JsonValue) = apply { this.callerLineno = callerLineno } + + /** + * The number of tokens in the completion generated by the model (only set if this is an + * LLM span) + */ + fun completionTokens(completionTokens: Long?) = + completionTokens(JsonField.ofNullable(completionTokens)) + + /** + * Alias for [Builder.completionTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun completionTokens(completionTokens: Long) = + completionTokens(completionTokens as Long?) + + /** + * Sets [Builder.completionTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.completionTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun completionTokens(completionTokens: JsonField) = apply { + this.completionTokens = completionTokens + } + + /** + * A unix timestamp recording when the section of code which produced the project logs + * event finished + */ + fun end(end: Double?) = end(JsonField.ofNullable(end)) + + /** + * Alias for [Builder.end]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun end(end: Double) = end(end as Double?) + + /** + * Sets [Builder.end] to an arbitrary JSON value. + * + * You should usually call [Builder.end] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun end(end: JsonField) = apply { this.end = end } + + /** + * The number of tokens in the prompt used to generate the project logs event (only set + * if this is an LLM span) + */ + fun promptTokens(promptTokens: Long?) = promptTokens(JsonField.ofNullable(promptTokens)) + + /** + * Alias for [Builder.promptTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun promptTokens(promptTokens: Long) = promptTokens(promptTokens as Long?) + + /** + * Sets [Builder.promptTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.promptTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptTokens(promptTokens: JsonField) = apply { + this.promptTokens = promptTokens + } + + /** + * A unix timestamp recording when the section of code which produced the project logs + * event started + */ + fun start(start: Double?) = start(JsonField.ofNullable(start)) + + /** + * Alias for [Builder.start]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun start(start: Double) = start(start as Double?) + + /** + * Sets [Builder.start] to an arbitrary JSON value. + * + * You should usually call [Builder.start] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun start(start: JsonField) = apply { this.start = start } + + /** The total number of tokens in the input and output of the project logs event. */ + fun tokens(tokens: Long?) = tokens(JsonField.ofNullable(tokens)) + + /** + * Alias for [Builder.tokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun tokens(tokens: Long) = tokens(tokens as Long?) + + /** + * Sets [Builder.tokens] to an arbitrary JSON value. + * + * You should usually call [Builder.tokens] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tokens(tokens: JsonField) = apply { this.tokens = tokens } + + 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 [Metrics]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Metrics = + Metrics( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Metrics = apply { + if (validated) { + return@apply + } + + completionTokens() + end() + promptTokens() + start() + tokens() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (completionTokens.asKnown() == null) 0 else 1) + + (if (end.asKnown() == null) 0 else 1) + + (if (promptTokens.asKnown() == null) 0 else 1) + + (if (start.asKnown() == null) 0 else 1) + + (if (tokens.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metrics && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + completionTokens == other.completionTokens && + end == other.end && + promptTokens == other.promptTokens && + start == other.start && + tokens == other.tokens && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metrics{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, completionTokens=$completionTokens, end=$end, promptTokens=$promptTokens, start=$start, tokens=$tokens, additionalProperties=$additionalProperties}" + } + + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare logs. + */ + class Scores + @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 [Scores]. */ + fun builder() = Builder() + } + + /** A builder for [Scores]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(scores: Scores) = apply { + additionalProperties = scores.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 [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Scores = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Scores && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Scores{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InsertProjectLogsEvent && + id == other.id && + _isMerge == other._isMerge && + _mergePaths == other._mergePaths && + _objectDelete == other._objectDelete && + _parentId == other._parentId && + context == other.context && + created == other.created && + error == other.error && + expected == other.expected && + input == other.input && + metadata == other.metadata && + metrics == other.metrics && + origin == other.origin && + output == other.output && + rootSpanId == other.rootSpanId && + scores == other.scores && + spanAttributes == other.spanAttributes && + spanId == other.spanId && + spanParents == other.spanParents && + tags == other.tags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + _isMerge, + _mergePaths, + _objectDelete, + _parentId, + context, + created, + error, + expected, + input, + metadata, + metrics, + origin, + output, + rootSpanId, + scores, + spanAttributes, + spanId, + spanParents, + tags, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InsertProjectLogsEvent{id=$id, _isMerge=$_isMerge, _mergePaths=$_mergePaths, _objectDelete=$_objectDelete, _parentId=$_parentId, context=$context, created=$created, error=$error, expected=$expected, input=$input, metadata=$metadata, metrics=$metrics, origin=$origin, output=$output, rootSpanId=$rootSpanId, scores=$scores, spanAttributes=$spanAttributes, spanId=$spanId, spanParents=$spanParents, tags=$tags, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventMerge.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventMerge.kt deleted file mode 100755 index 30b77d3c..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventMerge.kt +++ /dev/null @@ -1,1413 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.databind.annotation.JsonDeserialize -import java.time.OffsetDateTime -import java.util.Objects - -@JsonDeserialize(builder = InsertProjectLogsEventMerge.Builder::class) -@NoAutoDetect -class InsertProjectLogsEventMerge -private constructor( - private val input: JsonValue, - private val output: JsonValue, - private val expected: JsonValue, - private val error: JsonValue, - private val scores: JsonField, - private val metadata: JsonField, - private val tags: JsonField>, - private val metrics: JsonField, - private val context: JsonField, - private val spanAttributes: JsonField, - private val id: JsonField, - private val created: JsonField, - private val _objectDelete: JsonField, - private val _isMerge: JsonField, - private val _mergePaths: JsonField>>, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ - fun input(): JsonValue = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question. - */ - fun output(): JsonValue = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate while digging into - * analyses. However, we may later use these values to re-score outputs or fine-tune your - * models. - */ - fun expected(): JsonValue = expected - - /** The error that occurred, if any. */ - fun error(): JsonValue = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. - */ - fun scores(): Scores? = scores.getNullable("scores") - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - fun metadata(): Metadata? = metadata.getNullable("metadata") - - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project logs - * event was produced - */ - fun metrics(): Metrics? = metrics.getNullable("metrics") - - /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event - */ - fun context(): Context? = context.getNullable("context") - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(): String? = id.getNullable("id") - - /** The timestamp the project logs event was created */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will not - * show up in subsequent fetches for this project logs - */ - fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(): Boolean = _isMerge.getRequired("_is_merge") - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be specified - * alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of - * field names. The deep merge will not descend below any of the specified merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, - * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, - * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, - * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": - * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the - * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and - * `input.c`. - */ - fun _mergePaths(): List>? = _mergePaths.getNullable("_merge_paths") - - /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ - @JsonProperty("input") @ExcludeMissing fun _input() = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question. - */ - @JsonProperty("output") @ExcludeMissing fun _output() = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate while digging into - * analyses. However, we may later use these values to re-score outputs or fine-tune your - * models. - */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected - - /** The error that occurred, if any. */ - @JsonProperty("error") @ExcludeMissing fun _error() = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. - */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project logs - * event was produced - */ - @JsonProperty("metrics") @ExcludeMissing fun _metrics() = metrics - - /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event - */ - @JsonProperty("context") @ExcludeMissing fun _context() = context - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") @ExcludeMissing fun _spanAttributes() = spanAttributes - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** The timestamp the project logs event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will not - * show up in subsequent fetches for this project logs - */ - @JsonProperty("_object_delete") @ExcludeMissing fun __objectDelete() = _objectDelete - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge() = _isMerge - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be specified - * alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path is a list of - * field names. The deep merge will not descend below any of the specified merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": 10}, - * "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": true, - * "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": 30}, - * "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": {"a": {"q": - * 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this case, due to the - * merge paths, we have replaced `input.a` and `output`, but have still deep-merged `input` and - * `input.c`. - */ - @JsonProperty("_merge_paths") @ExcludeMissing fun __mergePaths() = _mergePaths - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InsertProjectLogsEventMerge = apply { - if (!validated) { - input() - output() - expected() - error() - scores()?.validate() - metadata()?.validate() - tags() - metrics()?.validate() - context()?.validate() - spanAttributes()?.validate() - id() - created() - _objectDelete() - _isMerge() - _mergePaths() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InsertProjectLogsEventMerge && - this.input == other.input && - this.output == other.output && - this.expected == other.expected && - this.error == other.error && - this.scores == other.scores && - this.metadata == other.metadata && - this.tags == other.tags && - this.metrics == other.metrics && - this.context == other.context && - this.spanAttributes == other.spanAttributes && - this.id == other.id && - this.created == other.created && - this._objectDelete == other._objectDelete && - this._isMerge == other._isMerge && - this._mergePaths == other._mergePaths && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - input, - output, - expected, - error, - scores, - metadata, - tags, - metrics, - context, - spanAttributes, - id, - created, - _objectDelete, - _isMerge, - _mergePaths, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InsertProjectLogsEventMerge{input=$input, output=$output, expected=$expected, error=$error, scores=$scores, metadata=$metadata, tags=$tags, metrics=$metrics, context=$context, spanAttributes=$spanAttributes, id=$id, created=$created, _objectDelete=$_objectDelete, _isMerge=$_isMerge, _mergePaths=$_mergePaths, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var input: JsonValue = JsonMissing.of() - private var output: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() - private var error: JsonValue = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var metrics: JsonField = JsonMissing.of() - private var context: JsonField = JsonMissing.of() - private var spanAttributes: JsonField = JsonMissing.of() - private var id: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var _objectDelete: JsonField = JsonMissing.of() - private var _isMerge: JsonField = JsonMissing.of() - private var _mergePaths: JsonField>> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(insertProjectLogsEventMerge: InsertProjectLogsEventMerge) = apply { - this.input = insertProjectLogsEventMerge.input - this.output = insertProjectLogsEventMerge.output - this.expected = insertProjectLogsEventMerge.expected - this.error = insertProjectLogsEventMerge.error - this.scores = insertProjectLogsEventMerge.scores - this.metadata = insertProjectLogsEventMerge.metadata - this.tags = insertProjectLogsEventMerge.tags - this.metrics = insertProjectLogsEventMerge.metrics - this.context = insertProjectLogsEventMerge.context - this.spanAttributes = insertProjectLogsEventMerge.spanAttributes - this.id = insertProjectLogsEventMerge.id - this.created = insertProjectLogsEventMerge.created - this._objectDelete = insertProjectLogsEventMerge._objectDelete - this._isMerge = insertProjectLogsEventMerge._isMerge - this._mergePaths = insertProjectLogsEventMerge._mergePaths - additionalProperties(insertProjectLogsEventMerge.additionalProperties) - } - - /** - * The arguments that uniquely define a user input (an arbitrary, JSON serializable object). - */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } - - /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object), that allows you to determine whether the result is correct or not. - * For example, in an app that generates SQL queries, the `output` should be the _result_ of - * the SQL query generated by the model, not the query itself, because there may be multiple - * valid queries that answer a single question. - */ - @JsonProperty("output") - @ExcludeMissing - fun output(output: JsonValue) = apply { this.output = output } - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does - * not compare `output` to `expected` for you, since there are so many different ways to do - * that correctly. Instead, these values are just used to help you navigate while digging - * into analyses. However, we may later use these values to re-score outputs or fine-tune - * your models. - */ - @JsonProperty("expected") - @ExcludeMissing - fun expected(expected: JsonValue) = apply { this.expected = expected } - - /** The error that occurred, if any. */ - @JsonProperty("error") - @ExcludeMissing - fun error(error: JsonValue) = apply { this.error = error } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare logs. - */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare logs. - */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project - * logs event was produced - */ - fun metrics(metrics: Metrics) = metrics(JsonField.of(metrics)) - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project - * logs event was produced - */ - @JsonProperty("metrics") - @ExcludeMissing - fun metrics(metrics: JsonField) = apply { this.metrics = metrics } - - /** - * Context is additional information about the code that produced the project logs event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the project logs event - */ - fun context(context: Context) = context(JsonField.of(context)) - - /** - * Context is additional information about the code that produced the project logs event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the project logs event - */ - @JsonProperty("context") - @ExcludeMissing - fun context(context: JsonField) = apply { this.context = context } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(spanAttributes: SpanAttributes) = - spanAttributes(JsonField.of(spanAttributes)) - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") - @ExcludeMissing - fun spanAttributes(spanAttributes: JsonField) = apply { - this.spanAttributes = spanAttributes - } - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(id: String) = id(JsonField.of(id)) - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** The timestamp the project logs event was created */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** The timestamp the project logs event was created */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will - * not show up in subsequent fetches for this project logs - */ - fun _objectDelete(_objectDelete: Boolean) = _objectDelete(JsonField.of(_objectDelete)) - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will - * not show up in subsequent fetches for this project logs - */ - @JsonProperty("_object_delete") - @ExcludeMissing - fun _objectDelete(_objectDelete: JsonField) = apply { - this._objectDelete = _objectDelete - } - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(_isMerge: Boolean) = _isMerge(JsonField.of(_isMerge)) - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") - @ExcludeMissing - fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be - * specified alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path - * is a list of field names. The deep merge will not descend below any of the specified - * merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": - * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": - * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": - * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": - * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this - * case, due to the merge paths, we have replaced `input.a` and `output`, but have still - * deep-merged `input` and `input.c`. - */ - fun _mergePaths(_mergePaths: List>) = _mergePaths(JsonField.of(_mergePaths)) - - /** - * The `_merge_paths` field allows controlling the depth of the merge. It can only be - * specified alongside `_is_merge=true`. `_merge_paths` is a list of paths, where each path - * is a list of field names. The deep merge will not descend below any of the specified - * merge paths. - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": {"b": - * 10}, "c": {"d": 20}}, "output": {"a": 20}}`. If we merge a new row as `{"_is_merge": - * true, "_merge_paths": [["input", "a"], ["output"]], "input": {"a": {"q": 30}, "c": {"e": - * 30}, "bar": "baz"}, "output": {"d": 40}}`, the new row will be `{"id": "foo": "input": - * {"a": {"q": 30}, "c": {"d": 20, "e": 30}, "bar": "baz"}, "output": {"d": 40}}`. In this - * case, due to the merge paths, we have replaced `input.a` and `output`, but have still - * deep-merged `input` and `input.c`. - */ - @JsonProperty("_merge_paths") - @ExcludeMissing - fun _mergePaths(_mergePaths: JsonField>>) = apply { - this._mergePaths = _mergePaths - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): InsertProjectLogsEventMerge = - InsertProjectLogsEventMerge( - input, - output, - expected, - error, - scores, - metadata, - tags.map { it.toUnmodifiable() }, - metrics, - context, - spanAttributes, - id, - created, - _objectDelete, - _isMerge, - _mergePaths.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), - ) - } - - /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event - */ - @JsonDeserialize(builder = Context.Builder::class) - @NoAutoDetect - class Context - private constructor( - private val callerFunctionname: JsonField, - private val callerFilename: JsonField, - private val callerLineno: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The function in code which created the project logs event */ - fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") - - /** Name of the file in code where the project logs event was created */ - fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - - /** Line of code where the project logs event was created */ - fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") - - /** The function in code which created the project logs event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun _callerFunctionname() = callerFunctionname - - /** Name of the file in code where the project logs event was created */ - @JsonProperty("caller_filename") @ExcludeMissing fun _callerFilename() = callerFilename - - /** Line of code where the project logs event was created */ - @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno() = callerLineno - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Context = apply { - if (!validated) { - callerFunctionname() - callerFilename() - callerLineno() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Context && - this.callerFunctionname == other.callerFunctionname && - this.callerFilename == other.callerFilename && - this.callerLineno == other.callerLineno && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Context{callerFunctionname=$callerFunctionname, callerFilename=$callerFilename, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var callerFunctionname: JsonField = JsonMissing.of() - private var callerFilename: JsonField = JsonMissing.of() - private var callerLineno: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(context: Context) = apply { - this.callerFunctionname = context.callerFunctionname - this.callerFilename = context.callerFilename - this.callerLineno = context.callerLineno - additionalProperties(context.additionalProperties) - } - - /** The function in code which created the project logs event */ - fun callerFunctionname(callerFunctionname: String) = - callerFunctionname(JsonField.of(callerFunctionname)) - - /** The function in code which created the project logs event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun callerFunctionname(callerFunctionname: JsonField) = apply { - this.callerFunctionname = callerFunctionname - } - - /** Name of the file in code where the project logs event was created */ - fun callerFilename(callerFilename: String) = - callerFilename(JsonField.of(callerFilename)) - - /** Name of the file in code where the project logs event was created */ - @JsonProperty("caller_filename") - @ExcludeMissing - fun callerFilename(callerFilename: JsonField) = apply { - this.callerFilename = callerFilename - } - - /** Line of code where the project logs event was created */ - fun callerLineno(callerLineno: Long) = callerLineno(JsonField.of(callerLineno)) - - /** Line of code where the project logs event was created */ - @JsonProperty("caller_lineno") - @ExcludeMissing - fun callerLineno(callerLineno: JsonField) = apply { - this.callerLineno = callerLineno - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Context = - Context( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project logs - * event was produced - */ - @JsonDeserialize(builder = Metrics.Builder::class) - @NoAutoDetect - class Metrics - private constructor( - private val start: JsonField, - private val end: JsonField, - private val promptTokens: JsonField, - private val completionTokens: JsonField, - private val tokens: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * started - */ - fun start(): Double? = start.getNullable("start") - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * finished - */ - fun end(): Double? = end.getNullable("end") - - /** - * The number of tokens in the prompt used to generate the project logs event (only set if - * this is an LLM span) - */ - fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") - - /** The total number of tokens in the input and output of the project logs event. */ - fun tokens(): Long? = tokens.getNullable("tokens") - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * started - */ - @JsonProperty("start") @ExcludeMissing fun _start() = start - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * finished - */ - @JsonProperty("end") @ExcludeMissing fun _end() = end - - /** - * The number of tokens in the prompt used to generate the project logs event (only set if - * this is an LLM span) - */ - @JsonProperty("prompt_tokens") @ExcludeMissing fun _promptTokens() = promptTokens - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun _completionTokens() = completionTokens - - /** The total number of tokens in the input and output of the project logs event. */ - @JsonProperty("tokens") @ExcludeMissing fun _tokens() = tokens - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metrics = apply { - if (!validated) { - start() - end() - promptTokens() - completionTokens() - tokens() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metrics && - this.start == other.start && - this.end == other.end && - this.promptTokens == other.promptTokens && - this.completionTokens == other.completionTokens && - this.tokens == other.tokens && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Metrics{start=$start, end=$end, promptTokens=$promptTokens, completionTokens=$completionTokens, tokens=$tokens, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var start: JsonField = JsonMissing.of() - private var end: JsonField = JsonMissing.of() - private var promptTokens: JsonField = JsonMissing.of() - private var completionTokens: JsonField = JsonMissing.of() - private var tokens: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metrics: Metrics) = apply { - this.start = metrics.start - this.end = metrics.end - this.promptTokens = metrics.promptTokens - this.completionTokens = metrics.completionTokens - this.tokens = metrics.tokens - additionalProperties(metrics.additionalProperties) - } - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event started - */ - fun start(start: Double) = start(JsonField.of(start)) - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event started - */ - @JsonProperty("start") - @ExcludeMissing - fun start(start: JsonField) = apply { this.start = start } - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event finished - */ - fun end(end: Double) = end(JsonField.of(end)) - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event finished - */ - @JsonProperty("end") - @ExcludeMissing - fun end(end: JsonField) = apply { this.end = end } - - /** - * The number of tokens in the prompt used to generate the project logs event (only set - * if this is an LLM span) - */ - fun promptTokens(promptTokens: Long) = promptTokens(JsonField.of(promptTokens)) - - /** - * The number of tokens in the prompt used to generate the project logs event (only set - * if this is an LLM span) - */ - @JsonProperty("prompt_tokens") - @ExcludeMissing - fun promptTokens(promptTokens: JsonField) = apply { - this.promptTokens = promptTokens - } - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - fun completionTokens(completionTokens: Long) = - completionTokens(JsonField.of(completionTokens)) - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun completionTokens(completionTokens: JsonField) = apply { - this.completionTokens = completionTokens - } - - /** The total number of tokens in the input and output of the project logs event. */ - fun tokens(tokens: Long) = tokens(JsonField.of(tokens)) - - /** The total number of tokens in the input and output of the project logs event. */ - @JsonProperty("tokens") - @ExcludeMissing - fun tokens(tokens: JsonField) = apply { this.tokens = tokens } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metrics = - Metrics( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Scores = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Scores && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Scores{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) - } - } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonDeserialize(builder = SpanAttributes.Builder::class) - @NoAutoDetect - class SpanAttributes - private constructor( - private val name: JsonField, - private val type: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Name of the span, for display purposes only */ - fun name(): String? = name.getNullable("name") - - /** Type of the span, for display purposes only */ - fun type(): Type? = type.getNullable("type") - - /** Name of the span, for display purposes only */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Type of the span, for display purposes only */ - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): SpanAttributes = apply { - if (!validated) { - name() - type() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SpanAttributes && - this.name == other.name && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SpanAttributes{name=$name, type=$type, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var name: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(spanAttributes: SpanAttributes) = apply { - this.name = spanAttributes.name - this.type = spanAttributes.type - additionalProperties(spanAttributes.additionalProperties) - } - - /** Name of the span, for display purposes only */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the span, for display purposes only */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - /** Type of the span, for display purposes only */ - fun type(type: Type) = type(JsonField.of(type)) - - /** Type of the span, for display purposes only */ - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): SpanAttributes = - SpanAttributes( - name, - type, - additionalProperties.toUnmodifiable(), - ) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val LLM = Type(JsonField.of("llm")) - - val SCORE = Type(JsonField.of("score")) - - val FUNCTION = Type(JsonField.of("function")) - - val EVAL = Type(JsonField.of("eval")) - - val TASK = Type(JsonField.of("task")) - - val TOOL = Type(JsonField.of("tool")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - } - - enum class Value { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - LLM -> Value.LLM - SCORE -> Value.SCORE - FUNCTION -> Value.FUNCTION - EVAL -> Value.EVAL - TASK -> Value.TASK - TOOL -> Value.TOOL - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - LLM -> Known.LLM - SCORE -> Known.SCORE - FUNCTION -> Known.FUNCTION - EVAL -> Known.EVAL - TASK -> Known.TASK - TOOL -> Known.TOOL - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventReplace.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventReplace.kt deleted file mode 100755 index 139f1175..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventReplace.kt +++ /dev/null @@ -1,1407 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.databind.annotation.JsonDeserialize -import java.time.OffsetDateTime -import java.util.Objects - -@JsonDeserialize(builder = InsertProjectLogsEventReplace.Builder::class) -@NoAutoDetect -class InsertProjectLogsEventReplace -private constructor( - private val input: JsonValue, - private val output: JsonValue, - private val expected: JsonValue, - private val error: JsonValue, - private val scores: JsonField, - private val metadata: JsonField, - private val tags: JsonField>, - private val metrics: JsonField, - private val context: JsonField, - private val spanAttributes: JsonField, - private val id: JsonField, - private val created: JsonField, - private val _objectDelete: JsonField, - private val _isMerge: JsonField, - private val _parentId: JsonField, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ - fun input(): JsonValue = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question. - */ - fun output(): JsonValue = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate while digging into - * analyses. However, we may later use these values to re-score outputs or fine-tune your - * models. - */ - fun expected(): JsonValue = expected - - /** The error that occurred, if any. */ - fun error(): JsonValue = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. - */ - fun scores(): Scores? = scores.getNullable("scores") - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - fun metadata(): Metadata? = metadata.getNullable("metadata") - - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project logs - * event was produced - */ - fun metrics(): Metrics? = metrics.getNullable("metrics") - - /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event - */ - fun context(): Context? = context.getNullable("context") - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(): String? = id.getNullable("id") - - /** The timestamp the project logs event was created */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will not - * show up in subsequent fetches for this project logs - */ - fun _objectDelete(): Boolean? = _objectDelete.getNullable("_object_delete") - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(): Boolean? = _isMerge.getNullable("_is_merge") - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot be - * specified alongside `_is_merge=true`. Tracking hierarchical relationships are important for - * tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent - * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after - * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row - * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this - * case, the `"llm_call"` row) by clicking on the "abc" row. - */ - fun _parentId(): String? = _parentId.getNullable("_parent_id") - - /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ - @JsonProperty("input") @ExcludeMissing fun _input() = input - - /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question. - */ - @JsonProperty("output") @ExcludeMissing fun _output() = output - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate while digging into - * analyses. However, we may later use these values to re-score outputs or fine-tune your - * models. - */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected - - /** The error that occurred, if any. */ - @JsonProperty("error") @ExcludeMissing fun _error() = error - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. - */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata - - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project logs - * event was produced - */ - @JsonProperty("metrics") @ExcludeMissing fun _metrics() = metrics - - /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event - */ - @JsonProperty("context") @ExcludeMissing fun _context() = context - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") @ExcludeMissing fun _spanAttributes() = spanAttributes - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** The timestamp the project logs event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will not - * show up in subsequent fetches for this project logs - */ - @JsonProperty("_object_delete") @ExcludeMissing fun __objectDelete() = _objectDelete - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same id - * in the DB. By default (or when set to `false`), the existing row is completely replaced by - * the new row. When set to `true`, the new row is deep-merged into the existing row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") @ExcludeMissing fun __isMerge() = _isMerge - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot be - * specified alongside `_is_merge=true`. Tracking hierarchical relationships are important for - * tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the parent - * row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What comes after - * foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the root span row - * `"abc"` will show up in the summary view. You can view the full trace hierarchy (in this - * case, the `"llm_call"` row) by clicking on the "abc" row. - */ - @JsonProperty("_parent_id") @ExcludeMissing fun __parentId() = _parentId - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): InsertProjectLogsEventReplace = apply { - if (!validated) { - input() - output() - expected() - error() - scores()?.validate() - metadata()?.validate() - tags() - metrics()?.validate() - context()?.validate() - spanAttributes()?.validate() - id() - created() - _objectDelete() - _isMerge() - _parentId() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is InsertProjectLogsEventReplace && - this.input == other.input && - this.output == other.output && - this.expected == other.expected && - this.error == other.error && - this.scores == other.scores && - this.metadata == other.metadata && - this.tags == other.tags && - this.metrics == other.metrics && - this.context == other.context && - this.spanAttributes == other.spanAttributes && - this.id == other.id && - this.created == other.created && - this._objectDelete == other._objectDelete && - this._isMerge == other._isMerge && - this._parentId == other._parentId && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - input, - output, - expected, - error, - scores, - metadata, - tags, - metrics, - context, - spanAttributes, - id, - created, - _objectDelete, - _isMerge, - _parentId, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "InsertProjectLogsEventReplace{input=$input, output=$output, expected=$expected, error=$error, scores=$scores, metadata=$metadata, tags=$tags, metrics=$metrics, context=$context, spanAttributes=$spanAttributes, id=$id, created=$created, _objectDelete=$_objectDelete, _isMerge=$_isMerge, _parentId=$_parentId, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var input: JsonValue = JsonMissing.of() - private var output: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() - private var error: JsonValue = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var metrics: JsonField = JsonMissing.of() - private var context: JsonField = JsonMissing.of() - private var spanAttributes: JsonField = JsonMissing.of() - private var id: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var _objectDelete: JsonField = JsonMissing.of() - private var _isMerge: JsonField = JsonMissing.of() - private var _parentId: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(insertProjectLogsEventReplace: InsertProjectLogsEventReplace) = apply { - this.input = insertProjectLogsEventReplace.input - this.output = insertProjectLogsEventReplace.output - this.expected = insertProjectLogsEventReplace.expected - this.error = insertProjectLogsEventReplace.error - this.scores = insertProjectLogsEventReplace.scores - this.metadata = insertProjectLogsEventReplace.metadata - this.tags = insertProjectLogsEventReplace.tags - this.metrics = insertProjectLogsEventReplace.metrics - this.context = insertProjectLogsEventReplace.context - this.spanAttributes = insertProjectLogsEventReplace.spanAttributes - this.id = insertProjectLogsEventReplace.id - this.created = insertProjectLogsEventReplace.created - this._objectDelete = insertProjectLogsEventReplace._objectDelete - this._isMerge = insertProjectLogsEventReplace._isMerge - this._parentId = insertProjectLogsEventReplace._parentId - additionalProperties(insertProjectLogsEventReplace.additionalProperties) - } - - /** - * The arguments that uniquely define a user input (an arbitrary, JSON serializable object). - */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } - - /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object), that allows you to determine whether the result is correct or not. - * For example, in an app that generates SQL queries, the `output` should be the _result_ of - * the SQL query generated by the model, not the query itself, because there may be multiple - * valid queries that answer a single question. - */ - @JsonProperty("output") - @ExcludeMissing - fun output(output: JsonValue) = apply { this.output = output } - - /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does - * not compare `output` to `expected` for you, since there are so many different ways to do - * that correctly. Instead, these values are just used to help you navigate while digging - * into analyses. However, we may later use these values to re-score outputs or fine-tune - * your models. - */ - @JsonProperty("expected") - @ExcludeMissing - fun expected(expected: JsonValue) = apply { this.expected = expected } - - /** The error that occurred, if any. */ - @JsonProperty("error") - @ExcludeMissing - fun error(error: JsonValue) = apply { this.error = error } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare logs. - */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare logs. - */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings - */ - @JsonProperty("metadata") - @ExcludeMissing - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project - * logs event was produced - */ - fun metrics(metrics: Metrics) = metrics(JsonField.of(metrics)) - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project - * logs event was produced - */ - @JsonProperty("metrics") - @ExcludeMissing - fun metrics(metrics: JsonField) = apply { this.metrics = metrics } - - /** - * Context is additional information about the code that produced the project logs event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the project logs event - */ - fun context(context: Context) = context(JsonField.of(context)) - - /** - * Context is additional information about the code that produced the project logs event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the project logs event - */ - @JsonProperty("context") - @ExcludeMissing - fun context(context: JsonField) = apply { this.context = context } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(spanAttributes: SpanAttributes) = - spanAttributes(JsonField.of(spanAttributes)) - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") - @ExcludeMissing - fun spanAttributes(spanAttributes: JsonField) = apply { - this.spanAttributes = spanAttributes - } - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - fun id(id: String) = id(JsonField.of(id)) - - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you - */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** The timestamp the project logs event was created */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** The timestamp the project logs event was created */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will - * not show up in subsequent fetches for this project logs - */ - fun _objectDelete(_objectDelete: Boolean) = _objectDelete(JsonField.of(_objectDelete)) - - /** - * Pass `_object_delete=true` to mark the project logs event deleted. Deleted events will - * not show up in subsequent fetches for this project logs - */ - @JsonProperty("_object_delete") - @ExcludeMissing - fun _objectDelete(_objectDelete: JsonField) = apply { - this._objectDelete = _objectDelete - } - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - fun _isMerge(_isMerge: Boolean) = _isMerge(JsonField.of(_isMerge)) - - /** - * The `_is_merge` field controls how the row is merged with any existing row with the same - * id in the DB. By default (or when set to `false`), the existing row is completely - * replaced by the new row. When set to `true`, the new row is deep-merged into the existing - * row - * - * For example, say there is an existing row in the DB `{"id": "foo", "input": {"a": 5, "b": - * 10}}`. If we merge a new row as `{"_is_merge": true, "id": "foo", "input": {"b": 11, "c": - * 20}}`, the new row will be `{"id": "foo", "input": {"a": 5, "b": 11, "c": 20}}`. If we - * replace the new row as `{"id": "foo", "input": {"b": 11, "c": 20}}`, the new row will be - * `{"id": "foo", "input": {"b": 11, "c": 20}}` - */ - @JsonProperty("_is_merge") - @ExcludeMissing - fun _isMerge(_isMerge: JsonField) = apply { this._isMerge = _isMerge } - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot - * be specified alongside `_is_merge=true`. Tracking hierarchical relationships are - * important for tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) - * for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the - * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What - * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the - * root span row `"abc"` will show up in the summary view. You can view the full trace - * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. - */ - fun _parentId(_parentId: String) = _parentId(JsonField.of(_parentId)) - - /** - * Use the `_parent_id` field to create this row as a subspan of an existing row. It cannot - * be specified alongside `_is_merge=true`. Tracking hierarchical relationships are - * important for tracing (see the [guide](https://www.braintrust.dev/docs/guides/tracing) - * for full details). - * - * For example, say we have logged a row `{"id": "abc", "input": "foo", "output": "bar", - * "expected": "boo", "scores": {"correctness": 0.33}}`. We can create a sub-span of the - * parent row by logging `{"_parent_id": "abc", "id": "llm_call", "input": {"prompt": "What - * comes after foo?"}, "output": "bar", "metrics": {"tokens": 1}}`. In the webapp, only the - * root span row `"abc"` will show up in the summary view. You can view the full trace - * hierarchy (in this case, the `"llm_call"` row) by clicking on the "abc" row. - */ - @JsonProperty("_parent_id") - @ExcludeMissing - fun _parentId(_parentId: JsonField) = apply { this._parentId = _parentId } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): InsertProjectLogsEventReplace = - InsertProjectLogsEventReplace( - input, - output, - expected, - error, - scores, - metadata, - tags.map { it.toUnmodifiable() }, - metrics, - context, - spanAttributes, - id, - created, - _objectDelete, - _isMerge, - _parentId, - additionalProperties.toUnmodifiable(), - ) - } - - /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event - */ - @JsonDeserialize(builder = Context.Builder::class) - @NoAutoDetect - class Context - private constructor( - private val callerFunctionname: JsonField, - private val callerFilename: JsonField, - private val callerLineno: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The function in code which created the project logs event */ - fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") - - /** Name of the file in code where the project logs event was created */ - fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - - /** Line of code where the project logs event was created */ - fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") - - /** The function in code which created the project logs event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun _callerFunctionname() = callerFunctionname - - /** Name of the file in code where the project logs event was created */ - @JsonProperty("caller_filename") @ExcludeMissing fun _callerFilename() = callerFilename - - /** Line of code where the project logs event was created */ - @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno() = callerLineno - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Context = apply { - if (!validated) { - callerFunctionname() - callerFilename() - callerLineno() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Context && - this.callerFunctionname == other.callerFunctionname && - this.callerFilename == other.callerFilename && - this.callerLineno == other.callerLineno && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Context{callerFunctionname=$callerFunctionname, callerFilename=$callerFilename, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var callerFunctionname: JsonField = JsonMissing.of() - private var callerFilename: JsonField = JsonMissing.of() - private var callerLineno: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(context: Context) = apply { - this.callerFunctionname = context.callerFunctionname - this.callerFilename = context.callerFilename - this.callerLineno = context.callerLineno - additionalProperties(context.additionalProperties) - } - - /** The function in code which created the project logs event */ - fun callerFunctionname(callerFunctionname: String) = - callerFunctionname(JsonField.of(callerFunctionname)) - - /** The function in code which created the project logs event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun callerFunctionname(callerFunctionname: JsonField) = apply { - this.callerFunctionname = callerFunctionname - } - - /** Name of the file in code where the project logs event was created */ - fun callerFilename(callerFilename: String) = - callerFilename(JsonField.of(callerFilename)) - - /** Name of the file in code where the project logs event was created */ - @JsonProperty("caller_filename") - @ExcludeMissing - fun callerFilename(callerFilename: JsonField) = apply { - this.callerFilename = callerFilename - } - - /** Line of code where the project logs event was created */ - fun callerLineno(callerLineno: Long) = callerLineno(JsonField.of(callerLineno)) - - /** Line of code where the project logs event was created */ - @JsonProperty("caller_lineno") - @ExcludeMissing - fun callerLineno(callerLineno: JsonField) = apply { - this.callerLineno = callerLineno - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Context = - Context( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings - */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metadata && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) - } - } - - /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project logs - * event was produced - */ - @JsonDeserialize(builder = Metrics.Builder::class) - @NoAutoDetect - class Metrics - private constructor( - private val start: JsonField, - private val end: JsonField, - private val promptTokens: JsonField, - private val completionTokens: JsonField, - private val tokens: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * started - */ - fun start(): Double? = start.getNullable("start") - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * finished - */ - fun end(): Double? = end.getNullable("end") - - /** - * The number of tokens in the prompt used to generate the project logs event (only set if - * this is an LLM span) - */ - fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") - - /** The total number of tokens in the input and output of the project logs event. */ - fun tokens(): Long? = tokens.getNullable("tokens") - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * started - */ - @JsonProperty("start") @ExcludeMissing fun _start() = start - - /** - * A unix timestamp recording when the section of code which produced the project logs event - * finished - */ - @JsonProperty("end") @ExcludeMissing fun _end() = end - - /** - * The number of tokens in the prompt used to generate the project logs event (only set if - * this is an LLM span) - */ - @JsonProperty("prompt_tokens") @ExcludeMissing fun _promptTokens() = promptTokens - - /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun _completionTokens() = completionTokens - - /** The total number of tokens in the input and output of the project logs event. */ - @JsonProperty("tokens") @ExcludeMissing fun _tokens() = tokens - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metrics = apply { - if (!validated) { - start() - end() - promptTokens() - completionTokens() - tokens() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metrics && - this.start == other.start && - this.end == other.end && - this.promptTokens == other.promptTokens && - this.completionTokens == other.completionTokens && - this.tokens == other.tokens && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Metrics{start=$start, end=$end, promptTokens=$promptTokens, completionTokens=$completionTokens, tokens=$tokens, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var start: JsonField = JsonMissing.of() - private var end: JsonField = JsonMissing.of() - private var promptTokens: JsonField = JsonMissing.of() - private var completionTokens: JsonField = JsonMissing.of() - private var tokens: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(metrics: Metrics) = apply { - this.start = metrics.start - this.end = metrics.end - this.promptTokens = metrics.promptTokens - this.completionTokens = metrics.completionTokens - this.tokens = metrics.tokens - additionalProperties(metrics.additionalProperties) - } - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event started - */ - fun start(start: Double) = start(JsonField.of(start)) - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event started - */ - @JsonProperty("start") - @ExcludeMissing - fun start(start: JsonField) = apply { this.start = start } - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event finished - */ - fun end(end: Double) = end(JsonField.of(end)) - - /** - * A unix timestamp recording when the section of code which produced the project logs - * event finished - */ - @JsonProperty("end") - @ExcludeMissing - fun end(end: JsonField) = apply { this.end = end } - - /** - * The number of tokens in the prompt used to generate the project logs event (only set - * if this is an LLM span) - */ - fun promptTokens(promptTokens: Long) = promptTokens(JsonField.of(promptTokens)) - - /** - * The number of tokens in the prompt used to generate the project logs event (only set - * if this is an LLM span) - */ - @JsonProperty("prompt_tokens") - @ExcludeMissing - fun promptTokens(promptTokens: JsonField) = apply { - this.promptTokens = promptTokens - } - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - fun completionTokens(completionTokens: Long) = - completionTokens(JsonField.of(completionTokens)) - - /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) - */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun completionTokens(completionTokens: JsonField) = apply { - this.completionTokens = completionTokens - } - - /** The total number of tokens in the input and output of the project logs event. */ - fun tokens(tokens: Long) = tokens(JsonField.of(tokens)) - - /** The total number of tokens in the input and output of the project logs event. */ - @JsonProperty("tokens") - @ExcludeMissing - fun tokens(tokens: JsonField) = apply { this.tokens = tokens } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Metrics = - Metrics( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties.toUnmodifiable(), - ) - } - } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Scores = apply { - if (!validated) { - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Scores && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Scores{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) - } - } - - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonDeserialize(builder = SpanAttributes.Builder::class) - @NoAutoDetect - class SpanAttributes - private constructor( - private val name: JsonField, - private val type: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Name of the span, for display purposes only */ - fun name(): String? = name.getNullable("name") - - /** Type of the span, for display purposes only */ - fun type(): Type? = type.getNullable("type") - - /** Name of the span, for display purposes only */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Type of the span, for display purposes only */ - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): SpanAttributes = apply { - if (!validated) { - name() - type() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SpanAttributes && - this.name == other.name && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SpanAttributes{name=$name, type=$type, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var name: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(spanAttributes: SpanAttributes) = apply { - this.name = spanAttributes.name - this.type = spanAttributes.type - additionalProperties(spanAttributes.additionalProperties) - } - - /** Name of the span, for display purposes only */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the span, for display purposes only */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - /** Type of the span, for display purposes only */ - fun type(type: Type) = type(JsonField.of(type)) - - /** Type of the span, for display purposes only */ - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): SpanAttributes = - SpanAttributes( - name, - type, - additionalProperties.toUnmodifiable(), - ) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val LLM = Type(JsonField.of("llm")) - - val SCORE = Type(JsonField.of("score")) - - val FUNCTION = Type(JsonField.of("function")) - - val EVAL = Type(JsonField.of("eval")) - - val TASK = Type(JsonField.of("task")) - - val TOOL = Type(JsonField.of("tool")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - } - - enum class Value { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - LLM -> Value.LLM - SCORE -> Value.SCORE - FUNCTION -> Value.FUNCTION - EVAL -> Value.EVAL - TASK -> Value.TASK - TOOL -> Value.TOOL - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - LLM -> Known.LLM - SCORE -> Known.SCORE - FUNCTION -> Known.FUNCTION - EVAL -> Known.EVAL - TASK -> Known.TASK - TOOL -> Known.TOOL - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/MetricSummary.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/MetricSummary.kt index fe0a1ffc..d7d9f8ab 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/MetricSummary.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/MetricSummary.kt @@ -6,216 +6,357 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** Summary of a metric's performance */ -@JsonDeserialize(builder = MetricSummary.Builder::class) -@NoAutoDetect class MetricSummary +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val name: JsonField, + private val improvements: JsonField, private val metric: JsonField, + private val name: JsonField, + private val regressions: JsonField, private val unit: JsonField, private val diff: JsonField, - private val improvements: JsonField, - private val regressions: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("improvements") + @ExcludeMissing + improvements: JsonField = JsonMissing.of(), + @JsonProperty("metric") @ExcludeMissing metric: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("regressions") + @ExcludeMissing + regressions: JsonField = JsonMissing.of(), + @JsonProperty("unit") @ExcludeMissing unit: JsonField = JsonMissing.of(), + @JsonProperty("diff") @ExcludeMissing diff: JsonField = JsonMissing.of(), + ) : this(improvements, metric, name, regressions, unit, diff, mutableMapOf()) + + /** + * Number of improvements in the metric + * + * @throws BraintrustInvalidDataException 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 improvements(): Long = improvements.getRequired("improvements") - private var hashCode: Int = 0 + /** + * Average metric across all examples + * + * @throws BraintrustInvalidDataException 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 metric(): Double = metric.getRequired("metric") - /** Name of the metric */ + /** + * Name of the metric + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** Average metric across all examples */ - fun metric(): Double = metric.getRequired("metric") + /** + * Number of regressions in the metric + * + * @throws BraintrustInvalidDataException 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 regressions(): Long = regressions.getRequired("regressions") - /** Unit label for the metric */ + /** + * Unit label for the metric + * + * @throws BraintrustInvalidDataException 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 unit(): String = unit.getRequired("unit") - /** Difference in metric between the current and comparison experiment */ + /** + * Difference in metric between the current and comparison experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun diff(): Double? = diff.getNullable("diff") - /** Number of improvements in the metric */ - fun improvements(): Long = improvements.getRequired("improvements") - - /** Number of regressions in the metric */ - fun regressions(): Long = regressions.getRequired("regressions") - - /** Name of the metric */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Average metric across all examples */ - @JsonProperty("metric") @ExcludeMissing fun _metric() = metric - - /** Unit label for the metric */ - @JsonProperty("unit") @ExcludeMissing fun _unit() = unit - - /** Difference in metric between the current and comparison experiment */ - @JsonProperty("diff") @ExcludeMissing fun _diff() = diff - - /** Number of improvements in the metric */ - @JsonProperty("improvements") @ExcludeMissing fun _improvements() = improvements - - /** Number of regressions in the metric */ - @JsonProperty("regressions") @ExcludeMissing fun _regressions() = regressions + /** + * Returns the raw JSON value of [improvements]. + * + * Unlike [improvements], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("improvements") + @ExcludeMissing + fun _improvements(): JsonField = improvements + + /** + * Returns the raw JSON value of [metric]. + * + * Unlike [metric], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metric") @ExcludeMissing fun _metric(): JsonField = metric + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [regressions]. + * + * Unlike [regressions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("regressions") @ExcludeMissing fun _regressions(): JsonField = regressions + + /** + * Returns the raw JSON value of [unit]. + * + * Unlike [unit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("unit") @ExcludeMissing fun _unit(): JsonField = unit + + /** + * Returns the raw JSON value of [diff]. + * + * Unlike [diff], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("diff") @ExcludeMissing fun _diff(): JsonField = diff + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): MetricSummary = apply { - if (!validated) { - name() - metric() - unit() - diff() - improvements() - regressions() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is MetricSummary && - this.name == other.name && - this.metric == other.metric && - this.unit == other.unit && - this.diff == other.diff && - this.improvements == other.improvements && - this.regressions == other.regressions && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - metric, - unit, - diff, - improvements, - regressions, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "MetricSummary{name=$name, metric=$metric, unit=$unit, diff=$diff, improvements=$improvements, regressions=$regressions, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [MetricSummary]. + * + * The following fields are required: + * ```kotlin + * .improvements() + * .metric() + * .name() + * .regressions() + * .unit() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [MetricSummary]. */ + class Builder internal constructor() { - private var name: JsonField = JsonMissing.of() - private var metric: JsonField = JsonMissing.of() - private var unit: JsonField = JsonMissing.of() + private var improvements: JsonField? = null + private var metric: JsonField? = null + private var name: JsonField? = null + private var regressions: JsonField? = null + private var unit: JsonField? = null private var diff: JsonField = JsonMissing.of() - private var improvements: JsonField = JsonMissing.of() - private var regressions: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metricSummary: MetricSummary) = apply { - this.name = metricSummary.name - this.metric = metricSummary.metric - this.unit = metricSummary.unit - this.diff = metricSummary.diff - this.improvements = metricSummary.improvements - this.regressions = metricSummary.regressions - additionalProperties(metricSummary.additionalProperties) + improvements = metricSummary.improvements + metric = metricSummary.metric + name = metricSummary.name + regressions = metricSummary.regressions + unit = metricSummary.unit + diff = metricSummary.diff + additionalProperties = metricSummary.additionalProperties.toMutableMap() } - /** Name of the metric */ - fun name(name: String) = name(JsonField.of(name)) + /** Number of improvements in the metric */ + fun improvements(improvements: Long) = improvements(JsonField.of(improvements)) - /** Name of the metric */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + /** + * Sets [Builder.improvements] to an arbitrary JSON value. + * + * You should usually call [Builder.improvements] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun improvements(improvements: JsonField) = apply { this.improvements = improvements } /** Average metric across all examples */ fun metric(metric: Double) = metric(JsonField.of(metric)) - /** Average metric across all examples */ - @JsonProperty("metric") - @ExcludeMissing + /** + * Sets [Builder.metric] to an arbitrary JSON value. + * + * You should usually call [Builder.metric] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun metric(metric: JsonField) = apply { this.metric = metric } + /** Name of the metric */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Number of regressions in the metric */ + fun regressions(regressions: Long) = regressions(JsonField.of(regressions)) + + /** + * Sets [Builder.regressions] to an arbitrary JSON value. + * + * You should usually call [Builder.regressions] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun regressions(regressions: JsonField) = apply { this.regressions = regressions } + /** Unit label for the metric */ fun unit(unit: String) = unit(JsonField.of(unit)) - /** Unit label for the metric */ - @JsonProperty("unit") - @ExcludeMissing + /** + * Sets [Builder.unit] to an arbitrary JSON value. + * + * You should usually call [Builder.unit] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun unit(unit: JsonField) = apply { this.unit = unit } /** Difference in metric between the current and comparison experiment */ fun diff(diff: Double) = diff(JsonField.of(diff)) - /** Difference in metric between the current and comparison experiment */ - @JsonProperty("diff") - @ExcludeMissing + /** + * Sets [Builder.diff] to an arbitrary JSON value. + * + * You should usually call [Builder.diff] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun diff(diff: JsonField) = apply { this.diff = diff } - /** Number of improvements in the metric */ - fun improvements(improvements: Long) = improvements(JsonField.of(improvements)) - - /** Number of improvements in the metric */ - @JsonProperty("improvements") - @ExcludeMissing - fun improvements(improvements: JsonField) = apply { this.improvements = improvements } - - /** Number of regressions in the metric */ - fun regressions(regressions: Long) = regressions(JsonField.of(regressions)) - - /** Number of regressions in the metric */ - @JsonProperty("regressions") - @ExcludeMissing - fun regressions(regressions: JsonField) = apply { this.regressions = regressions } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [MetricSummary]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .improvements() + * .metric() + * .name() + * .regressions() + * .unit() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): MetricSummary = MetricSummary( - name, - metric, - unit, + checkRequired("improvements", improvements), + checkRequired("metric", metric), + checkRequired("name", name), + checkRequired("regressions", regressions), + checkRequired("unit", unit), diff, - improvements, - regressions, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): MetricSummary = apply { + if (validated) { + return@apply + } + + improvements() + metric() + name() + regressions() + unit() + diff() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (improvements.asKnown() == null) 0 else 1) + + (if (metric.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (regressions.asKnown() == null) 0 else 1) + + (if (unit.asKnown() == null) 0 else 1) + + (if (diff.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MetricSummary && + improvements == other.improvements && + metric == other.metric && + name == other.name && + regressions == other.regressions && + unit == other.unit && + diff == other.diff && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(improvements, metric, name, regressions, unit, diff, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "MetricSummary{improvements=$improvements, metric=$metric, name=$name, regressions=$regressions, unit=$unit, diff=$diff, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ObjectReference.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ObjectReference.kt new file mode 100644 index 00000000..5ab6f7d8 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ObjectReference.kt @@ -0,0 +1,476 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Enum +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 + +/** Indicates the event was copied from another object. */ +class ObjectReference +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val _xactId: JsonField, + private val objectId: JsonField, + private val objectType: JsonField, + private val created: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_xact_id") @ExcludeMissing _xactId: JsonField = JsonMissing.of(), + @JsonProperty("object_id") @ExcludeMissing objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("created") @ExcludeMissing created: JsonField = JsonMissing.of(), + ) : this(id, _xactId, objectId, objectType, created, mutableMapOf()) + + /** + * ID of the original event. + * + * @throws BraintrustInvalidDataException 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") + + /** + * Transaction ID of the original event. + * + * @throws BraintrustInvalidDataException 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 _xactId(): String = _xactId.getRequired("_xact_id") + + /** + * ID of the object the event is originating from. + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + + /** + * Type of the object the event is originating from. + * + * @throws BraintrustInvalidDataException 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 objectType(): ObjectType = objectType.getRequired("object_type") + + /** + * Created timestamp of the original event. Used to help sort in the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): String? = created.getNullable("created") + + /** + * 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 [_xactId]. + * + * Unlike [_xactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_xact_id") @ExcludeMissing fun __xactId(): JsonField = _xactId + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + @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 [ObjectReference]. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ObjectReference]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var _xactId: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var created: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(objectReference: ObjectReference) = apply { + id = objectReference.id + _xactId = objectReference._xactId + objectId = objectReference.objectId + objectType = objectReference.objectType + created = objectReference.created + additionalProperties = objectReference.additionalProperties.toMutableMap() + } + + /** ID of the original 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 } + + /** Transaction ID of the original event. */ + fun _xactId(_xactId: String) = _xactId(JsonField.of(_xactId)) + + /** + * Sets [Builder._xactId] to an arbitrary JSON value. + * + * You should usually call [Builder._xactId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun _xactId(_xactId: JsonField) = apply { this._xactId = _xactId } + + /** ID of the object the event is originating from. */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + + /** Type of the object the event is originating from. */ + fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [ObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { this.objectType = objectType } + + /** Created timestamp of the original event. Used to help sort in the UI */ + fun created(created: String?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun created(created: JsonField) = apply { this.created = created } + + 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 [ObjectReference]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ObjectReference = + ObjectReference( + checkRequired("id", id), + checkRequired("_xactId", _xactId), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + created, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ObjectReference = apply { + if (validated) { + return@apply + } + + id() + _xactId() + objectId() + objectType().validate() + created() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_xactId.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (created.asKnown() == null) 0 else 1) + + /** Type of the object the event is originating from. */ + class ObjectType @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 { + + val EXPERIMENT = of("experiment") + + val DATASET = of("dataset") + + val PROMPT = of("prompt") + + val FUNCTION = of("function") + + val PROMPT_SESSION = of("prompt_session") + + val PROJECT_LOGS = of("project_logs") + + fun of(value: String) = ObjectType(JsonField.of(value)) + } + + /** An enum containing [ObjectType]'s known values. */ + enum class Known { + EXPERIMENT, + DATASET, + PROMPT, + FUNCTION, + PROMPT_SESSION, + PROJECT_LOGS, + } + + /** + * An enum containing [ObjectType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ObjectType] 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 { + EXPERIMENT, + DATASET, + PROMPT, + FUNCTION, + PROMPT_SESSION, + PROJECT_LOGS, + /** + * An enum member indicating that [ObjectType] 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) { + EXPERIMENT -> Value.EXPERIMENT + DATASET -> Value.DATASET + PROMPT -> Value.PROMPT + FUNCTION -> Value.FUNCTION + PROMPT_SESSION -> Value.PROMPT_SESSION + PROJECT_LOGS -> Value.PROJECT_LOGS + 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + EXPERIMENT -> Known.EXPERIMENT + DATASET -> Known.DATASET + PROMPT -> Known.PROMPT + FUNCTION -> Known.FUNCTION + PROMPT_SESSION -> Known.PROMPT_SESSION + PROJECT_LOGS -> Known.PROJECT_LOGS + else -> throw BraintrustInvalidDataException("Unknown ObjectType: $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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ObjectType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ObjectType && 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 ObjectReference && + id == other.id && + _xactId == other._xactId && + objectId == other.objectId && + objectType == other.objectType && + created == other.created && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, _xactId, objectId, objectType, created, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ObjectReference{id=$id, _xactId=$_xactId, objectId=$objectId, objectType=$objectType, created=$created, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OnlineScoreConfig.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OnlineScoreConfig.kt index 978e93b5..aa87cb78 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OnlineScoreConfig.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OnlineScoreConfig.kt @@ -9,9 +9,11 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -24,120 +26,155 @@ 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 -@JsonDeserialize(builder = OnlineScoreConfig.Builder::class) -@NoAutoDetect class OnlineScoreConfig +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val samplingRate: JsonField, private val scorers: JsonField>, private val applyToRootSpan: JsonField, private val applyToSpanNames: JsonField>, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** The sampling rate for online scoring */ + @JsonCreator + private constructor( + @JsonProperty("sampling_rate") + @ExcludeMissing + samplingRate: JsonField = JsonMissing.of(), + @JsonProperty("scorers") + @ExcludeMissing + scorers: JsonField> = JsonMissing.of(), + @JsonProperty("apply_to_root_span") + @ExcludeMissing + applyToRootSpan: JsonField = JsonMissing.of(), + @JsonProperty("apply_to_span_names") + @ExcludeMissing + applyToSpanNames: JsonField> = JsonMissing.of(), + ) : this(samplingRate, scorers, applyToRootSpan, applyToSpanNames, mutableMapOf()) + + /** + * The sampling rate for online scoring + * + * @throws BraintrustInvalidDataException 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 samplingRate(): Double = samplingRate.getRequired("sampling_rate") - /** The list of scorers to use for online scoring */ + /** + * The list of scorers to use for online scoring + * + * @throws BraintrustInvalidDataException 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 scorers(): List = scorers.getRequired("scorers") - /** Whether to trigger online scoring on the root span of each trace */ + /** + * Whether to trigger online scoring on the root span of each trace + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun applyToRootSpan(): Boolean? = applyToRootSpan.getNullable("apply_to_root_span") - /** Trigger online scoring on any spans with a name in this list */ + /** + * Trigger online scoring on any spans with a name in this list + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun applyToSpanNames(): List? = applyToSpanNames.getNullable("apply_to_span_names") - /** The sampling rate for online scoring */ - @JsonProperty("sampling_rate") @ExcludeMissing fun _samplingRate() = samplingRate - - /** The list of scorers to use for online scoring */ - @JsonProperty("scorers") @ExcludeMissing fun _scorers() = scorers - - /** Whether to trigger online scoring on the root span of each trace */ - @JsonProperty("apply_to_root_span") @ExcludeMissing fun _applyToRootSpan() = applyToRootSpan + /** + * Returns the raw JSON value of [samplingRate]. + * + * Unlike [samplingRate], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sampling_rate") + @ExcludeMissing + fun _samplingRate(): JsonField = samplingRate + + /** + * Returns the raw JSON value of [scorers]. + * + * Unlike [scorers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scorers") @ExcludeMissing fun _scorers(): JsonField> = scorers + + /** + * Returns the raw JSON value of [applyToRootSpan]. + * + * Unlike [applyToRootSpan], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("apply_to_root_span") + @ExcludeMissing + fun _applyToRootSpan(): JsonField = applyToRootSpan + + /** + * Returns the raw JSON value of [applyToSpanNames]. + * + * Unlike [applyToSpanNames], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("apply_to_span_names") + @ExcludeMissing + fun _applyToSpanNames(): JsonField> = applyToSpanNames - /** Trigger online scoring on any spans with a name in this list */ - @JsonProperty("apply_to_span_names") @ExcludeMissing fun _applyToSpanNames() = applyToSpanNames + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): OnlineScoreConfig = apply { - if (!validated) { - samplingRate() - scorers() - applyToRootSpan() - applyToSpanNames() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is OnlineScoreConfig && - this.samplingRate == other.samplingRate && - this.scorers == other.scorers && - this.applyToRootSpan == other.applyToRootSpan && - this.applyToSpanNames == other.applyToSpanNames && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - samplingRate, - scorers, - applyToRootSpan, - applyToSpanNames, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "OnlineScoreConfig{samplingRate=$samplingRate, scorers=$scorers, applyToRootSpan=$applyToRootSpan, applyToSpanNames=$applyToSpanNames, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [OnlineScoreConfig]. + * + * The following fields are required: + * ```kotlin + * .samplingRate() + * .scorers() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [OnlineScoreConfig]. */ + class Builder internal constructor() { - private var samplingRate: JsonField = JsonMissing.of() - private var scorers: JsonField> = JsonMissing.of() + private var samplingRate: JsonField? = null + private var scorers: JsonField>? = null private var applyToRootSpan: JsonField = JsonMissing.of() - private var applyToSpanNames: JsonField> = JsonMissing.of() + private var applyToSpanNames: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(onlineScoreConfig: OnlineScoreConfig) = apply { - this.samplingRate = onlineScoreConfig.samplingRate - this.scorers = onlineScoreConfig.scorers - this.applyToRootSpan = onlineScoreConfig.applyToRootSpan - this.applyToSpanNames = onlineScoreConfig.applyToSpanNames - additionalProperties(onlineScoreConfig.additionalProperties) + samplingRate = onlineScoreConfig.samplingRate + scorers = onlineScoreConfig.scorers.map { it.toMutableList() } + applyToRootSpan = onlineScoreConfig.applyToRootSpan + applyToSpanNames = onlineScoreConfig.applyToSpanNames.map { it.toMutableList() } + additionalProperties = onlineScoreConfig.additionalProperties.toMutableMap() } /** The sampling rate for online scoring */ fun samplingRate(samplingRate: Double) = samplingRate(JsonField.of(samplingRate)) - /** The sampling rate for online scoring */ - @JsonProperty("sampling_rate") - @ExcludeMissing + /** + * Sets [Builder.samplingRate] to an arbitrary JSON value. + * + * You should usually call [Builder.samplingRate] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun samplingRate(samplingRate: JsonField) = apply { this.samplingRate = samplingRate } @@ -145,57 +182,159 @@ private constructor( /** The list of scorers to use for online scoring */ fun scorers(scorers: List) = scorers(JsonField.of(scorers)) - /** The list of scorers to use for online scoring */ - @JsonProperty("scorers") - @ExcludeMissing - fun scorers(scorers: JsonField>) = apply { this.scorers = scorers } + /** + * Sets [Builder.scorers] to an arbitrary JSON value. + * + * You should usually call [Builder.scorers] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun scorers(scorers: JsonField>) = apply { + this.scorers = scorers.map { it.toMutableList() } + } - /** Whether to trigger online scoring on the root span of each trace */ - fun applyToRootSpan(applyToRootSpan: Boolean) = - applyToRootSpan(JsonField.of(applyToRootSpan)) + /** + * Adds a single [Scorer] to [scorers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addScorer(scorer: Scorer) = apply { + scorers = + (scorers ?: JsonField.of(mutableListOf())).also { + checkKnown("scorers", it).add(scorer) + } + } + + /** Alias for calling [addScorer] with `Scorer.ofFunction(function)`. */ + fun addScorer(function: Scorer.Function) = addScorer(Scorer.ofFunction(function)) + + /** Alias for calling [addScorer] with `Scorer.ofGlobal(global)`. */ + fun addScorer(global: Scorer.Global) = addScorer(Scorer.ofGlobal(global)) /** Whether to trigger online scoring on the root span of each trace */ - @JsonProperty("apply_to_root_span") - @ExcludeMissing + fun applyToRootSpan(applyToRootSpan: Boolean?) = + applyToRootSpan(JsonField.ofNullable(applyToRootSpan)) + + /** + * Alias for [Builder.applyToRootSpan]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun applyToRootSpan(applyToRootSpan: Boolean) = applyToRootSpan(applyToRootSpan as Boolean?) + + /** + * Sets [Builder.applyToRootSpan] to an arbitrary JSON value. + * + * You should usually call [Builder.applyToRootSpan] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun applyToRootSpan(applyToRootSpan: JsonField) = apply { this.applyToRootSpan = applyToRootSpan } /** Trigger online scoring on any spans with a name in this list */ - fun applyToSpanNames(applyToSpanNames: List) = - applyToSpanNames(JsonField.of(applyToSpanNames)) - - /** Trigger online scoring on any spans with a name in this list */ - @JsonProperty("apply_to_span_names") - @ExcludeMissing + fun applyToSpanNames(applyToSpanNames: List?) = + applyToSpanNames(JsonField.ofNullable(applyToSpanNames)) + + /** + * Sets [Builder.applyToSpanNames] to an arbitrary JSON value. + * + * You should usually call [Builder.applyToSpanNames] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun applyToSpanNames(applyToSpanNames: JsonField>) = apply { - this.applyToSpanNames = applyToSpanNames + this.applyToSpanNames = applyToSpanNames.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [applyToSpanNames]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addApplyToSpanName(applyToSpanName: String) = apply { + applyToSpanNames = + (applyToSpanNames ?: JsonField.of(mutableListOf())).also { + checkKnown("applyToSpanNames", it).add(applyToSpanName) + } } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [OnlineScoreConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .samplingRate() + * .scorers() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): OnlineScoreConfig = OnlineScoreConfig( - samplingRate, - scorers.map { it.toUnmodifiable() }, + checkRequired("samplingRate", samplingRate), + checkRequired("scorers", scorers).map { it.toImmutable() }, applyToRootSpan, - applyToSpanNames.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + (applyToSpanNames ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): OnlineScoreConfig = apply { + if (validated) { + return@apply + } + + samplingRate() + scorers().forEach { it.validate() } + applyToRootSpan() + applyToSpanNames() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (samplingRate.asKnown() == null) 0 else 1) + + (scorers.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (if (applyToRootSpan.asKnown() == null) 0 else 1) + + (applyToSpanNames.asKnown()?.size ?: 0) + @JsonDeserialize(using = Scorer.Deserializer::class) @JsonSerialize(using = Scorer.Serializer::class) class Scorer @@ -205,8 +344,6 @@ private constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun function(): Function? = function fun global(): Global? = global @@ -221,45 +358,76 @@ private constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { function != null -> visitor.visitFunction(function) global != null -> visitor.visitGlobal(global) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Scorer = apply { - if (!validated) { - if (function == null && global == null) { - throw BraintrustInvalidDataException("Unknown Scorer: $_json") - } - function?.validate() - global?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitFunction(function: Function) { + function.validate() + } + + override fun visitGlobal(global: Global) { + global.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitFunction(function: Function) = function.validity() + + override fun visitGlobal(global: Global) = global.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Scorer && this.function == other.function && this.global == other.global + return other is Scorer && function == other.function && global == other.global } - override fun hashCode(): Int { - return Objects.hash(function, global) - } + override fun hashCode(): Int = Objects.hash(function, global) - override fun toString(): String { - return when { + override fun toString(): String = + when { function != null -> "Scorer{function=$function}" global != null -> "Scorer{global=$global}" _json != null -> "Scorer{_unknown=$_json}" else -> throw IllegalStateException("Invalid Scorer") } - } companion object { @@ -268,40 +436,64 @@ private constructor( fun ofGlobal(global: Global) = Scorer(global = global) } + /** An interface that defines how to map each variant of [Scorer] to a value of type [T]. */ interface Visitor { fun visitFunction(function: Function): T fun visitGlobal(global: Global): T + /** + * Maps an unknown variant of [Scorer] to a value of type [T]. + * + * An instance of [Scorer] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Scorer: $json") } } - class Deserializer : BaseDeserializer(Scorer::class) { + internal class Deserializer : BaseDeserializer(Scorer::class) { override fun ObjectCodec.deserialize(node: JsonNode): Scorer { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Scorer(function = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Scorer(global = it, _json = json) - } - return Scorer(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Scorer(function = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Scorer(global = 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 -> Scorer(_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() + } } } - class Serializer : BaseSerializer(Scorer::class) { + internal class Serializer : BaseSerializer(Scorer::class) { override fun serialize( value: Scorer, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.function != null -> generator.writeObject(value.function) @@ -312,104 +504,116 @@ private constructor( } } - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val type: JsonField, private val id: JsonField, - private val additionalProperties: Map, + private val type: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun type(): Type = type.getRequired("type") - + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(id, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("id") @ExcludeMissing fun _id() = id + /** + * 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 [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 = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - type() - id() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Function && - this.type == other.type && - this.id == other.id && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - id, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Function{type=$type, id=$id, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Function]. + * + * The following fields are required: + * ```kotlin + * .id() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Function]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var id: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(function: Function) = apply { - this.type = function.type - this.id = function.id - additionalProperties(function.additionalProperties) + id = function.id + type = function.type + additionalProperties = function.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun id(id: String) = id(JsonField.of(id)) - @JsonProperty("id") - @ExcludeMissing + /** + * 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 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -417,164 +621,316 @@ private constructor( 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Function = Function( - type, - id, - additionalProperties.toUnmodifiable(), + checkRequired("id", id), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Function = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + id() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val FUNCTION = Type(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - FUNCTION, + FUNCTION } + /** + * 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 { FUNCTION, + /** + * 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) { FUNCTION -> Value.FUNCTION 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { FUNCTION -> Known.FUNCTION else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - - @JsonDeserialize(builder = Global.Builder::class) - @NoAutoDetect - class Global - private constructor( - private val type: JsonField, - private val name: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun name(): String = name.getRequired("name") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("name") @ExcludeMissing fun _name() = name + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Global = apply { - if (!validated) { - type() - name() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Global && - this.type == other.type && - this.name == other.name && - this.additionalProperties == other.additionalProperties + return other is Function && + id == other.id && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - name, - additionalProperties, - ) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(id, type, additionalProperties) } + + override fun hashCode(): Int = hashCode override fun toString() = - "Global{type=$type, name=$name, additionalProperties=$additionalProperties}" + "Function{id=$id, type=$type, additionalProperties=$additionalProperties}" + } + + class Global + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [Global]. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Global]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var name: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(global: Global) = apply { - this.type = global.type - this.name = global.name - additionalProperties(global.additionalProperties) + name = global.name + type = global.type + additionalProperties = global.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -582,64 +938,226 @@ private constructor( 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 [Global]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Global = Global( - type, - name, - additionalProperties.toUnmodifiable(), + checkRequired("name", name), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Global = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val GLOBAL = Type(JsonField.of("global")) + val GLOBAL = of("global") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - GLOBAL, + GLOBAL } + /** + * 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 { GLOBAL, + /** + * 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) { GLOBAL -> Value.GLOBAL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { GLOBAL -> Known.GLOBAL else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Global && + name == other.name && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Global{name=$name, type=$type, additionalProperties=$additionalProperties}" } } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is OnlineScoreConfig && + samplingRate == other.samplingRate && + scorers == other.scorers && + applyToRootSpan == other.applyToRootSpan && + applyToSpanNames == other.applyToSpanNames && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(samplingRate, scorers, applyToRootSpan, applyToSpanNames, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "OnlineScoreConfig{samplingRate=$samplingRate, scorers=$scorers, applyToRootSpan=$applyToRootSpan, applyToSpanNames=$applyToSpanNames, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Organization.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Organization.kt index 4badd1ed..fc5cbd05 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Organization.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Organization.kt @@ -6,221 +6,397 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = Organization.Builder::class) -@NoAutoDetect class Organization +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val name: JsonField, private val apiUrl: JsonField, + private val created: JsonField, private val isUniversalApi: JsonField, private val proxyUrl: JsonField, private val realtimeUrl: JsonField, - private val created: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the organization */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("api_url") @ExcludeMissing apiUrl: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("is_universal_api") + @ExcludeMissing + isUniversalApi: JsonField = JsonMissing.of(), + @JsonProperty("proxy_url") @ExcludeMissing proxyUrl: JsonField = JsonMissing.of(), + @JsonProperty("realtime_url") + @ExcludeMissing + realtimeUrl: JsonField = JsonMissing.of(), + ) : this(id, name, apiUrl, created, isUniversalApi, proxyUrl, realtimeUrl, mutableMapOf()) + + /** + * Unique identifier for the organization + * + * @throws BraintrustInvalidDataException 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") - /** Name of the organization */ + /** + * Name of the organization + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun apiUrl(): String? = apiUrl.getNullable("api_url") + /** + * Date of organization creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun isUniversalApi(): Boolean? = isUniversalApi.getNullable("is_universal_api") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun proxyUrl(): String? = proxyUrl.getNullable("proxy_url") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun realtimeUrl(): String? = realtimeUrl.getNullable("realtime_url") - /** Date of organization creation */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** Unique identifier for the organization */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Name of the organization */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonProperty("api_url") @ExcludeMissing fun _apiUrl() = apiUrl - - @JsonProperty("is_universal_api") @ExcludeMissing fun _isUniversalApi() = isUniversalApi - - @JsonProperty("proxy_url") @ExcludeMissing fun _proxyUrl() = proxyUrl - - @JsonProperty("realtime_url") @ExcludeMissing fun _realtimeUrl() = realtimeUrl + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [apiUrl]. + * + * Unlike [apiUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("api_url") @ExcludeMissing fun _apiUrl(): JsonField = apiUrl + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [isUniversalApi]. + * + * Unlike [isUniversalApi], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("is_universal_api") + @ExcludeMissing + fun _isUniversalApi(): JsonField = isUniversalApi + + /** + * Returns the raw JSON value of [proxyUrl]. + * + * Unlike [proxyUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("proxy_url") @ExcludeMissing fun _proxyUrl(): JsonField = proxyUrl + + /** + * Returns the raw JSON value of [realtimeUrl]. + * + * Unlike [realtimeUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("realtime_url") + @ExcludeMissing + fun _realtimeUrl(): JsonField = realtimeUrl - /** Date of organization creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Organization = apply { - if (!validated) { - id() - name() - apiUrl() - isUniversalApi() - proxyUrl() - realtimeUrl() - created() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Organization && - this.id == other.id && - this.name == other.name && - this.apiUrl == other.apiUrl && - this.isUniversalApi == other.isUniversalApi && - this.proxyUrl == other.proxyUrl && - this.realtimeUrl == other.realtimeUrl && - this.created == other.created && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - name, - apiUrl, - isUniversalApi, - proxyUrl, - realtimeUrl, - created, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Organization{id=$id, name=$name, apiUrl=$apiUrl, isUniversalApi=$isUniversalApi, proxyUrl=$proxyUrl, realtimeUrl=$realtimeUrl, created=$created, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Organization]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Organization]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null private var apiUrl: JsonField = JsonMissing.of() + private var created: JsonField = JsonMissing.of() private var isUniversalApi: JsonField = JsonMissing.of() private var proxyUrl: JsonField = JsonMissing.of() private var realtimeUrl: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(organization: Organization) = apply { - this.id = organization.id - this.name = organization.name - this.apiUrl = organization.apiUrl - this.isUniversalApi = organization.isUniversalApi - this.proxyUrl = organization.proxyUrl - this.realtimeUrl = organization.realtimeUrl - this.created = organization.created - additionalProperties(organization.additionalProperties) + id = organization.id + name = organization.name + apiUrl = organization.apiUrl + created = organization.created + isUniversalApi = organization.isUniversalApi + proxyUrl = organization.proxyUrl + realtimeUrl = organization.realtimeUrl + additionalProperties = organization.additionalProperties.toMutableMap() } /** Unique identifier for the organization */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the organization */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } /** Name of the organization */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the organization */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } - fun apiUrl(apiUrl: String) = apiUrl(JsonField.of(apiUrl)) + fun apiUrl(apiUrl: String?) = apiUrl(JsonField.ofNullable(apiUrl)) - @JsonProperty("api_url") - @ExcludeMissing + /** + * Sets [Builder.apiUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.apiUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun apiUrl(apiUrl: JsonField) = apply { this.apiUrl = apiUrl } - fun isUniversalApi(isUniversalApi: Boolean) = isUniversalApi(JsonField.of(isUniversalApi)) + /** Date of organization creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } - @JsonProperty("is_universal_api") - @ExcludeMissing + fun isUniversalApi(isUniversalApi: Boolean?) = + isUniversalApi(JsonField.ofNullable(isUniversalApi)) + + /** + * Alias for [Builder.isUniversalApi]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun isUniversalApi(isUniversalApi: Boolean) = isUniversalApi(isUniversalApi as Boolean?) + + /** + * Sets [Builder.isUniversalApi] to an arbitrary JSON value. + * + * You should usually call [Builder.isUniversalApi] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun isUniversalApi(isUniversalApi: JsonField) = apply { this.isUniversalApi = isUniversalApi } - fun proxyUrl(proxyUrl: String) = proxyUrl(JsonField.of(proxyUrl)) + fun proxyUrl(proxyUrl: String?) = proxyUrl(JsonField.ofNullable(proxyUrl)) - @JsonProperty("proxy_url") - @ExcludeMissing + /** + * Sets [Builder.proxyUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.proxyUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun proxyUrl(proxyUrl: JsonField) = apply { this.proxyUrl = proxyUrl } - fun realtimeUrl(realtimeUrl: String) = realtimeUrl(JsonField.of(realtimeUrl)) + fun realtimeUrl(realtimeUrl: String?) = realtimeUrl(JsonField.ofNullable(realtimeUrl)) - @JsonProperty("realtime_url") - @ExcludeMissing + /** + * Sets [Builder.realtimeUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.realtimeUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun realtimeUrl(realtimeUrl: JsonField) = apply { this.realtimeUrl = realtimeUrl } - /** Date of organization creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** Date of organization creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Organization]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Organization = Organization( - id, - name, + checkRequired("id", id), + checkRequired("name", name), apiUrl, + created, isUniversalApi, proxyUrl, realtimeUrl, - created, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): Organization = apply { + if (validated) { + return@apply + } + + id() + name() + apiUrl() + created() + isUniversalApi() + proxyUrl() + realtimeUrl() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (apiUrl.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (isUniversalApi.asKnown() == null) 0 else 1) + + (if (proxyUrl.asKnown() == null) 0 else 1) + + (if (realtimeUrl.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Organization && + id == other.id && + name == other.name && + apiUrl == other.apiUrl && + created == other.created && + isUniversalApi == other.isUniversalApi && + proxyUrl == other.proxyUrl && + realtimeUrl == other.realtimeUrl && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + apiUrl, + created, + isUniversalApi, + proxyUrl, + realtimeUrl, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Organization{id=$id, name=$name, apiUrl=$apiUrl, created=$created, isUniversalApi=$isUniversalApi, proxyUrl=$proxyUrl, realtimeUrl=$realtimeUrl, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationDeleteParams.kt index 3b40e3f9..e192176a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationDeleteParams.kt @@ -3,138 +3,167 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete an organization object by its id */ class OrganizationDeleteParams -constructor( - private val organizationId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val organizationId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun organizationId(): String = organizationId + /** Organization id */ + fun organizationId(): String? = organizationId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> organizationId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): OrganizationDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [OrganizationDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [OrganizationDeleteParams]. */ + class Builder internal constructor() { + + private var organizationId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalHeaders(): Map> = additionalHeaders + internal fun from(organizationDeleteParams: OrganizationDeleteParams) = apply { + organizationId = organizationDeleteParams.organizationId + additionalHeaders = organizationDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = organizationDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + organizationDeleteParams.additionalBodyProperties.toMutableMap() + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + /** Organization id */ + fun organizationId(organizationId: String?) = apply { this.organizationId = organizationId } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is OrganizationDeleteParams && - this.organizationId == other.organizationId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - organizationId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "OrganizationDeleteParams{organizationId=$organizationId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var organizationId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(organizationDeleteParams: OrganizationDeleteParams) = apply { - this.organizationId = organizationDeleteParams.organizationId - additionalQueryParams(organizationDeleteParams.additionalQueryParams) - additionalHeaders(organizationDeleteParams.additionalHeaders) - additionalBodyProperties(organizationDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Organization id */ - fun organizationId(organizationId: String) = apply { this.organizationId = organizationId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +171,60 @@ constructor( 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 [OrganizationDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): OrganizationDeleteParams = OrganizationDeleteParams( - checkNotNull(organizationId) { "`organizationId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + organizationId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> organizationId ?: "" + 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 OrganizationDeleteParams && + organizationId == other.organizationId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash( + organizationId, + additionalHeaders, + additionalQueryParams, + additionalBodyProperties, + ) + + override fun toString() = + "OrganizationDeleteParams{organizationId=$organizationId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPage.kt index 63fcefa0..6287ad6b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPage.kt @@ -2,182 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.OrganizationService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see OrganizationService.list */ class OrganizationListPage private constructor( - private val organizationsService: OrganizationService, + private val service: OrganizationService, private val params: OrganizationListParams, - private val response: Response, -) { + private val response: OrganizationListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [OrganizationListPageResponse], but gracefully handles missing data. + * + * @see OrganizationListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is OrganizationListPage && - this.organizationsService == other.organizationsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - organizationsService, - params, - response, - ) - } - - override fun toString() = - "OrganizationListPage{organizationsService=$organizationsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): OrganizationListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - OrganizationListParams.builder() - .from(params) - .endingBefore(objects().first().id()) - .build() + fun nextPageParams(): OrganizationListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - OrganizationListParams.builder() - .from(params) - .startingAfter(objects().last().id()) - .build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): OrganizationListPage? { - return getNextPageParams()?.let { organizationsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - organizationsService: OrganizationService, - params: OrganizationListParams, - response: Response - ) = - OrganizationListPage( - organizationsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): OrganizationListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): OrganizationListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): OrganizationListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [OrganizationListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [OrganizationListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: OrganizationService? = null + private var params: OrganizationListParams? = null + private var response: OrganizationListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(organizationListPage: OrganizationListPage) = apply { + service = organizationListPage.service + params = organizationListPage.params + response = organizationListPage.response } - override fun toString() = - "OrganizationListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: OrganizationService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: OrganizationListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: OrganizationListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [OrganizationListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): OrganizationListPage = + OrganizationListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is OrganizationListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: OrganizationListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "OrganizationListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPageAsync.kt index dfd308a5..3a92d223 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPageAsync.kt @@ -2,184 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.OrganizationServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see OrganizationServiceAsync.list */ class OrganizationListPageAsync private constructor( - private val organizationsService: OrganizationServiceAsync, + private val service: OrganizationServiceAsync, private val params: OrganizationListParams, - private val response: Response, -) { + private val response: OrganizationListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [OrganizationListPageResponse], but gracefully handles missing data. + * + * @see OrganizationListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is OrganizationListPageAsync && - this.organizationsService == other.organizationsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - organizationsService, - params, - response, - ) - } - - override fun toString() = - "OrganizationListPageAsync{organizationsService=$organizationsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): OrganizationListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - OrganizationListParams.builder() - .from(params) - .endingBefore(objects().first().id()) - .build() + fun nextPageParams(): OrganizationListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - OrganizationListParams.builder() - .from(params) - .startingAfter(objects().last().id()) - .build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): OrganizationListPageAsync? { - return getNextPageParams()?.let { organizationsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - organizationsService: OrganizationServiceAsync, - params: OrganizationListParams, - response: Response - ) = - OrganizationListPageAsync( - organizationsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): OrganizationListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): OrganizationListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): OrganizationListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [OrganizationListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [OrganizationListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: OrganizationServiceAsync? = null + private var params: OrganizationListParams? = null + private var response: OrganizationListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(organizationListPageAsync: OrganizationListPageAsync) = apply { + service = organizationListPageAsync.service + params = organizationListPageAsync.params + response = organizationListPageAsync.response } - override fun toString() = - "OrganizationListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: OrganizationServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: OrganizationListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: OrganizationListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [OrganizationListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): OrganizationListPageAsync = + OrganizationListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is OrganizationListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: OrganizationListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "OrganizationListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPageResponse.kt new file mode 100644 index 00000000..fd9fc68b --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 OrganizationListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of organization objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [OrganizationListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [OrganizationListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(organizationListPageResponse: OrganizationListPageResponse) = apply { + objects = organizationListPageResponse.objects.map { it.toMutableList() } + additionalProperties = organizationListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of organization objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Organization] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Organization) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [OrganizationListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): OrganizationListPageResponse = + OrganizationListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): OrganizationListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is OrganizationListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "OrganizationListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListParams.kt index b570466f..2844434c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationListParams.kt @@ -2,117 +2,93 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all organizations. The organizations are sorted by creation date, with the most + * recently-created organizations coming first + */ class OrganizationListParams -constructor( +private constructor( private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, private val orgName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is OrganizationListParams && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - ids, - limit, - orgName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "OrganizationListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): OrganizationListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [OrganizationListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [OrganizationListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var ids: Ids? = null private var limit: Long? = null private var orgName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(organizationListParams: OrganizationListParams) = apply { - this.endingBefore = organizationListParams.endingBefore - this.ids = organizationListParams.ids - this.limit = organizationListParams.limit - this.orgName = organizationListParams.orgName - this.startingAfter = organizationListParams.startingAfter - additionalQueryParams(organizationListParams.additionalQueryParams) - additionalHeaders(organizationListParams.additionalHeaders) + endingBefore = organizationListParams.endingBefore + ids = organizationListParams.ids + limit = organizationListParams.limit + orgName = organizationListParams.orgName + startingAfter = organizationListParams.startingAfter + additionalHeaders = organizationListParams.additionalHeaders.toBuilder() + additionalQueryParams = organizationListParams.additionalQueryParams.toBuilder() } /** @@ -122,31 +98,32 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** * Pagination cursor id. @@ -155,48 +132,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [OrganizationListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): OrganizationListParams = OrganizationListParams( endingBefore, @@ -204,22 +244,45 @@ constructor( limit, orgName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -232,93 +295,72 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is OrganizationListParams && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + ids, + limit, + orgName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "OrganizationListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParams.kt index 91a966ee..18f96b14 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParams.kt @@ -3,597 +3,1284 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** Modify organization membership */ class OrganizationMemberUpdateParams -constructor( - private val inviteUsers: InviteUsers?, - private val orgId: String?, - private val orgName: String?, - private val removeUsers: RemoveUsers?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun inviteUsers(): InviteUsers? = inviteUsers - - fun orgId(): String? = orgId - - fun orgName(): String? = orgName - - fun removeUsers(): RemoveUsers? = removeUsers - - internal fun getBody(): OrganizationMemberUpdateBody { - return OrganizationMemberUpdateBody( - inviteUsers, - orgId, - orgName, - removeUsers, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Users to invite to the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun inviteUsers(): InviteUsers? = body.inviteUsers() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, or in case you want to explicitly assert the + * organization you are modifying, you may specify the id of the organization. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgId(): String? = body.orgId() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, or in case you want to explicitly assert the + * organization you are modifying, you may specify the name of the organization. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Users to remove from the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun removeUsers(): RemoveUsers? = body.removeUsers() + + /** + * Returns the raw JSON value of [inviteUsers]. + * + * Unlike [inviteUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _inviteUsers(): JsonField = body._inviteUsers() + + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgId(): JsonField = body._orgId() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + /** + * Returns the raw JSON value of [removeUsers]. + * + * Unlike [removeUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _removeUsers(): JsonField = body._removeUsers() + + 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 { + + fun none(): OrganizationMemberUpdateParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of + * [OrganizationMemberUpdateParams]. + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [OrganizationMemberUpdateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = OrganizationMemberUpdateBody.Builder::class) - @NoAutoDetect - class OrganizationMemberUpdateBody - internal constructor( - private val inviteUsers: InviteUsers?, - private val orgId: String?, - private val orgName: String?, - private val removeUsers: RemoveUsers?, - private val additionalProperties: Map, - ) { + internal fun from(organizationMemberUpdateParams: OrganizationMemberUpdateParams) = apply { + body = organizationMemberUpdateParams.body.toBuilder() + additionalHeaders = organizationMemberUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = organizationMemberUpdateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [inviteUsers] + * - [orgId] + * - [orgName] + * - [removeUsers] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Users to invite to the organization */ - @JsonProperty("invite_users") fun inviteUsers(): InviteUsers? = inviteUsers + fun inviteUsers(inviteUsers: InviteUsers?) = apply { body.inviteUsers(inviteUsers) } + + /** + * Sets [Builder.inviteUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.inviteUsers] with a well-typed [InviteUsers] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun inviteUsers(inviteUsers: JsonField) = apply { + body.inviteUsers(inviteUsers) + } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, or in case you want to explicitly assert * the organization you are modifying, you may specify the id of the organization. */ - @JsonProperty("org_id") fun orgId(): String? = orgId + fun orgId(orgId: String?) = apply { body.orgId(orgId) } + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgId(orgId: JsonField) = apply { body.orgId(orgId) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, or in case you want to explicitly assert * the organization you are modifying, you may specify the name of the organization. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } /** Users to remove from the organization */ - @JsonProperty("remove_users") fun removeUsers(): RemoveUsers? = removeUsers + fun removeUsers(removeUsers: RemoveUsers?) = apply { body.removeUsers(removeUsers) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.removeUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.removeUsers] with a well-typed [RemoveUsers] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun removeUsers(removeUsers: JsonField) = apply { + body.removeUsers(removeUsers) + } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is OrganizationMemberUpdateBody && - this.inviteUsers == other.inviteUsers && - this.orgId == other.orgId && - this.orgName == other.orgName && - this.removeUsers == other.removeUsers && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - inviteUsers, - orgId, - orgName, - removeUsers, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "OrganizationMemberUpdateBody{inviteUsers=$inviteUsers, orgId=$orgId, orgName=$orgName, removeUsers=$removeUsers, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var inviteUsers: InviteUsers? = null - private var orgId: String? = null - private var orgName: String? = null - private var removeUsers: RemoveUsers? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(organizationMemberUpdateBody: OrganizationMemberUpdateBody) = apply { - this.inviteUsers = organizationMemberUpdateBody.inviteUsers - this.orgId = organizationMemberUpdateBody.orgId - this.orgName = organizationMemberUpdateBody.orgName - this.removeUsers = organizationMemberUpdateBody.removeUsers - additionalProperties(organizationMemberUpdateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Users to invite to the organization */ - @JsonProperty("invite_users") - fun inviteUsers(inviteUsers: InviteUsers) = apply { this.inviteUsers = inviteUsers } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, or in case you want to explicitly - * assert the organization you are modifying, you may specify the id of the - * organization. - */ - @JsonProperty("org_id") fun orgId(orgId: String) = apply { this.orgId = orgId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, or in case you want to explicitly - * assert the organization you are modifying, you may specify the name of the - * organization. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Users to remove from the organization */ - @JsonProperty("remove_users") - fun removeUsers(removeUsers: RemoveUsers) = apply { this.removeUsers = removeUsers } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): OrganizationMemberUpdateBody = - OrganizationMemberUpdateBody( - inviteUsers, - orgId, - orgName, - removeUsers, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is OrganizationMemberUpdateParams && - this.inviteUsers == other.inviteUsers && - this.orgId == other.orgId && - this.orgName == other.orgName && - this.removeUsers == other.removeUsers && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - inviteUsers, - orgId, - orgName, - removeUsers, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "OrganizationMemberUpdateParams{inviteUsers=$inviteUsers, orgId=$orgId, orgName=$orgName, removeUsers=$removeUsers, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [OrganizationMemberUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): OrganizationMemberUpdateParams = + OrganizationMemberUpdateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var inviteUsers: InviteUsers? = null - private var orgId: String? = null - private var orgName: String? = null - private var removeUsers: RemoveUsers? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(organizationMemberUpdateParams: OrganizationMemberUpdateParams) = apply { - this.inviteUsers = organizationMemberUpdateParams.inviteUsers - this.orgId = organizationMemberUpdateParams.orgId - this.orgName = organizationMemberUpdateParams.orgName - this.removeUsers = organizationMemberUpdateParams.removeUsers - additionalQueryParams(organizationMemberUpdateParams.additionalQueryParams) - additionalHeaders(organizationMemberUpdateParams.additionalHeaders) - additionalBodyProperties(organizationMemberUpdateParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Users to invite to the organization */ - fun inviteUsers(inviteUsers: InviteUsers) = apply { this.inviteUsers = inviteUsers } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val inviteUsers: JsonField, + private val orgId: JsonField, + private val orgName: JsonField, + private val removeUsers: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("invite_users") + @ExcludeMissing + inviteUsers: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + @JsonProperty("remove_users") + @ExcludeMissing + removeUsers: JsonField = JsonMissing.of(), + ) : this(inviteUsers, orgId, orgName, removeUsers, mutableMapOf()) + + /** + * Users to invite to the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun inviteUsers(): InviteUsers? = inviteUsers.getNullable("invite_users") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, or in case you want to explicitly assert * the organization you are modifying, you may specify the id of the organization. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgId(orgId: String) = apply { this.orgId = orgId } + fun orgId(): String? = orgId.getNullable("org_id") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, or in case you want to explicitly assert * the organization you are modifying, you may specify the name of the organization. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - /** Users to remove from the organization */ - fun removeUsers(removeUsers: RemoveUsers) = apply { this.removeUsers = removeUsers } + /** + * Users to remove from the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun removeUsers(): RemoveUsers? = removeUsers.getNullable("remove_users") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [inviteUsers]. + * + * Unlike [inviteUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("invite_users") + @ExcludeMissing + fun _inviteUsers(): JsonField = inviteUsers - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [removeUsers]. + * + * Unlike [removeUsers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("remove_users") + @ExcludeMissing + fun _removeUsers(): JsonField = removeUsers - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var inviteUsers: JsonField = JsonMissing.of() + private var orgId: JsonField = JsonMissing.of() + private var orgName: JsonField = JsonMissing.of() + private var removeUsers: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + inviteUsers = body.inviteUsers + orgId = body.orgId + orgName = body.orgName + removeUsers = body.removeUsers + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Users to invite to the organization */ + fun inviteUsers(inviteUsers: InviteUsers?) = + inviteUsers(JsonField.ofNullable(inviteUsers)) + + /** + * Sets [Builder.inviteUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.inviteUsers] with a well-typed [InviteUsers] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun inviteUsers(inviteUsers: JsonField) = apply { + this.inviteUsers = inviteUsers + } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, or in case you want to explicitly + * assert the organization you are modifying, you may specify the id of the + * organization. + */ + fun orgId(orgId: String?) = orgId(JsonField.ofNullable(orgId)) + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgId(orgId: JsonField) = apply { this.orgId = orgId } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, or in case you want to explicitly + * assert the organization you are modifying, you may specify the name of the + * organization. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + /** Users to remove from the organization */ + fun removeUsers(removeUsers: RemoveUsers?) = + removeUsers(JsonField.ofNullable(removeUsers)) + + /** + * Sets [Builder.removeUsers] to an arbitrary JSON value. + * + * You should usually call [Builder.removeUsers] with a well-typed [RemoveUsers] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun removeUsers(removeUsers: JsonField) = apply { + this.removeUsers = removeUsers + } + + 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(inviteUsers, orgId, orgName, removeUsers, additionalProperties.toMutableMap()) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + inviteUsers()?.validate() + orgId() + orgName() + removeUsers()?.validate() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (inviteUsers.asKnown()?.validity() ?: 0) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (orgName.asKnown() == null) 0 else 1) + + (removeUsers.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + inviteUsers == other.inviteUsers && + orgId == other.orgId && + orgName == other.orgName && + removeUsers == other.removeUsers && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(inviteUsers, orgId, orgName, removeUsers, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): OrganizationMemberUpdateParams = - OrganizationMemberUpdateParams( - inviteUsers, - orgId, - orgName, - removeUsers, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{inviteUsers=$inviteUsers, orgId=$orgId, orgName=$orgName, removeUsers=$removeUsers, additionalProperties=$additionalProperties}" } /** Users to invite to the organization */ - @JsonDeserialize(builder = InviteUsers.Builder::class) - @NoAutoDetect class InviteUsers + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val ids: List?, - private val emails: List?, - private val sendInviteEmails: Boolean?, - private val groupIds: List?, - private val groupNames: List?, - private val groupId: String?, - private val groupName: String?, - private val additionalProperties: Map, + private val emails: JsonField>, + private val groupId: JsonField, + private val groupIds: JsonField>, + private val groupName: JsonField, + private val groupNames: JsonField>, + private val ids: JsonField>, + private val sendInviteEmails: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("emails") + @ExcludeMissing + emails: JsonField> = JsonMissing.of(), + @JsonProperty("group_id") @ExcludeMissing groupId: JsonField = JsonMissing.of(), + @JsonProperty("group_ids") + @ExcludeMissing + groupIds: JsonField> = JsonMissing.of(), + @JsonProperty("group_name") + @ExcludeMissing + groupName: JsonField = JsonMissing.of(), + @JsonProperty("group_names") + @ExcludeMissing + groupNames: JsonField> = JsonMissing.of(), + @JsonProperty("ids") @ExcludeMissing ids: JsonField> = JsonMissing.of(), + @JsonProperty("send_invite_emails") + @ExcludeMissing + sendInviteEmails: JsonField = JsonMissing.of(), + ) : this( + emails, + groupId, + groupIds, + groupName, + groupNames, + ids, + sendInviteEmails, + mutableMapOf(), + ) - /** Ids of existing users to invite */ - @JsonProperty("ids") fun ids(): List? = ids + /** + * Emails of users to invite + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun emails(): List? = emails.getNullable("emails") - /** Emails of users to invite */ - @JsonProperty("emails") fun emails(): List? = emails + /** + * Singular form of group_ids + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun groupId(): String? = groupId.getNullable("group_id") - /** If true, send invite emails to the users who wore actually added */ - @JsonProperty("send_invite_emails") fun sendInviteEmails(): Boolean? = sendInviteEmails + /** + * Optional list of group ids to add newly-invited users to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun groupIds(): List? = groupIds.getNullable("group_ids") - /** Optional list of group ids to add newly-invited users to. */ - @JsonProperty("group_ids") fun groupIds(): List? = groupIds + /** + * Singular form of group_names + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun groupName(): String? = groupName.getNullable("group_name") + + /** + * Optional list of group names to add newly-invited users to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun groupNames(): List? = groupNames.getNullable("group_names") + + /** + * Ids of existing users to invite + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun ids(): List? = ids.getNullable("ids") - /** Optional list of group names to add newly-invited users to. */ - @JsonProperty("group_names") fun groupNames(): List? = groupNames + /** + * If true, send invite emails to the users who wore actually added + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun sendInviteEmails(): Boolean? = sendInviteEmails.getNullable("send_invite_emails") - /** Singular form of group_ids */ - @JsonProperty("group_id") fun groupId(): String? = groupId + /** + * Returns the raw JSON value of [emails]. + * + * Unlike [emails], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("emails") @ExcludeMissing fun _emails(): JsonField> = emails - /** Singular form of group_names */ - @JsonProperty("group_name") fun groupName(): String? = groupName + /** + * Returns the raw JSON value of [groupId]. + * + * Unlike [groupId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_id") @ExcludeMissing fun _groupId(): JsonField = groupId - @JsonAnyGetter + /** + * Returns the raw JSON value of [groupIds]. + * + * Unlike [groupIds], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_ids") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _groupIds(): JsonField> = groupIds - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [groupName]. + * + * Unlike [groupName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_name") @ExcludeMissing fun _groupName(): JsonField = groupName - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [groupNames]. + * + * Unlike [groupNames], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("group_names") + @ExcludeMissing + fun _groupNames(): JsonField> = groupNames - return other is InviteUsers && - this.ids == other.ids && - this.emails == other.emails && - this.sendInviteEmails == other.sendInviteEmails && - this.groupIds == other.groupIds && - this.groupNames == other.groupNames && - this.groupId == other.groupId && - this.groupName == other.groupName && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - ids, - emails, - sendInviteEmails, - groupIds, - groupNames, - groupId, - groupName, - additionalProperties, - ) - } - return hashCode + /** + * Returns the raw JSON value of [ids]. + * + * Unlike [ids], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("ids") @ExcludeMissing fun _ids(): JsonField> = ids + + /** + * Returns the raw JSON value of [sendInviteEmails]. + * + * Unlike [sendInviteEmails], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("send_invite_emails") + @ExcludeMissing + fun _sendInviteEmails(): JsonField = sendInviteEmails + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "InviteUsers{ids=$ids, emails=$emails, sendInviteEmails=$sendInviteEmails, groupIds=$groupIds, groupNames=$groupNames, groupId=$groupId, groupName=$groupName, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [InviteUsers]. */ fun builder() = Builder() } - class Builder { + /** A builder for [InviteUsers]. */ + class Builder internal constructor() { - private var ids: List? = null - private var emails: List? = null - private var sendInviteEmails: Boolean? = null - private var groupIds: List? = null - private var groupNames: List? = null - private var groupId: String? = null - private var groupName: String? = null + private var emails: JsonField>? = null + private var groupId: JsonField = JsonMissing.of() + private var groupIds: JsonField>? = null + private var groupName: JsonField = JsonMissing.of() + private var groupNames: JsonField>? = null + private var ids: JsonField>? = null + private var sendInviteEmails: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(inviteUsers: InviteUsers) = apply { - this.ids = inviteUsers.ids - this.emails = inviteUsers.emails - this.sendInviteEmails = inviteUsers.sendInviteEmails - this.groupIds = inviteUsers.groupIds - this.groupNames = inviteUsers.groupNames - this.groupId = inviteUsers.groupId - this.groupName = inviteUsers.groupName - additionalProperties(inviteUsers.additionalProperties) + emails = inviteUsers.emails.map { it.toMutableList() } + groupId = inviteUsers.groupId + groupIds = inviteUsers.groupIds.map { it.toMutableList() } + groupName = inviteUsers.groupName + groupNames = inviteUsers.groupNames.map { it.toMutableList() } + ids = inviteUsers.ids.map { it.toMutableList() } + sendInviteEmails = inviteUsers.sendInviteEmails + additionalProperties = inviteUsers.additionalProperties.toMutableMap() } - /** Ids of existing users to invite */ - @JsonProperty("ids") fun ids(ids: List) = apply { this.ids = ids } - /** Emails of users to invite */ - @JsonProperty("emails") - fun emails(emails: List) = apply { this.emails = emails } + fun emails(emails: List?) = emails(JsonField.ofNullable(emails)) - /** If true, send invite emails to the users who wore actually added */ - @JsonProperty("send_invite_emails") - fun sendInviteEmails(sendInviteEmails: Boolean) = apply { - this.sendInviteEmails = sendInviteEmails + /** + * Sets [Builder.emails] to an arbitrary JSON value. + * + * You should usually call [Builder.emails] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun emails(emails: JsonField>) = apply { + this.emails = emails.map { it.toMutableList() } } + /** + * Adds a single [String] to [emails]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEmail(email: String) = apply { + emails = + (emails ?: JsonField.of(mutableListOf())).also { + checkKnown("emails", it).add(email) + } + } + + /** Singular form of group_ids */ + fun groupId(groupId: String?) = groupId(JsonField.ofNullable(groupId)) + + /** + * Sets [Builder.groupId] to an arbitrary JSON value. + * + * You should usually call [Builder.groupId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupId(groupId: JsonField) = apply { this.groupId = groupId } + /** Optional list of group ids to add newly-invited users to. */ - @JsonProperty("group_ids") - fun groupIds(groupIds: List) = apply { this.groupIds = groupIds } + fun groupIds(groupIds: List?) = groupIds(JsonField.ofNullable(groupIds)) - /** Optional list of group names to add newly-invited users to. */ - @JsonProperty("group_names") - fun groupNames(groupNames: List) = apply { this.groupNames = groupNames } + /** + * Sets [Builder.groupIds] to an arbitrary JSON value. + * + * You should usually call [Builder.groupIds] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupIds(groupIds: JsonField>) = apply { + this.groupIds = groupIds.map { it.toMutableList() } + } - /** Singular form of group_ids */ - @JsonProperty("group_id") - fun groupId(groupId: String) = apply { this.groupId = groupId } + /** + * Adds a single [String] to [groupIds]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addGroupId(groupId: String) = apply { + groupIds = + (groupIds ?: JsonField.of(mutableListOf())).also { + checkKnown("groupIds", it).add(groupId) + } + } /** Singular form of group_names */ - @JsonProperty("group_name") - fun groupName(groupName: String) = apply { this.groupName = groupName } + fun groupName(groupName: String?) = groupName(JsonField.ofNullable(groupName)) + + /** + * Sets [Builder.groupName] to an arbitrary JSON value. + * + * You should usually call [Builder.groupName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupName(groupName: JsonField) = apply { this.groupName = groupName } + + /** Optional list of group names to add newly-invited users to. */ + fun groupNames(groupNames: List?) = groupNames(JsonField.ofNullable(groupNames)) + + /** + * Sets [Builder.groupNames] to an arbitrary JSON value. + * + * You should usually call [Builder.groupNames] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun groupNames(groupNames: JsonField>) = apply { + this.groupNames = groupNames.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [groupNames]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addGroupName(groupName: String) = apply { + groupNames = + (groupNames ?: JsonField.of(mutableListOf())).also { + checkKnown("groupNames", it).add(groupName) + } + } + + /** Ids of existing users to invite */ + fun ids(ids: List?) = ids(JsonField.ofNullable(ids)) + + /** + * Sets [Builder.ids] to an arbitrary JSON value. + * + * You should usually call [Builder.ids] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun ids(ids: JsonField>) = apply { + this.ids = ids.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [ids]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addId(id: String) = apply { + ids = (ids ?: JsonField.of(mutableListOf())).also { checkKnown("ids", it).add(id) } + } + + /** If true, send invite emails to the users who wore actually added */ + fun sendInviteEmails(sendInviteEmails: Boolean?) = + sendInviteEmails(JsonField.ofNullable(sendInviteEmails)) + + /** + * Alias for [Builder.sendInviteEmails]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun sendInviteEmails(sendInviteEmails: Boolean) = + sendInviteEmails(sendInviteEmails as Boolean?) + + /** + * Sets [Builder.sendInviteEmails] to an arbitrary JSON value. + * + * You should usually call [Builder.sendInviteEmails] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun sendInviteEmails(sendInviteEmails: JsonField) = apply { + this.sendInviteEmails = sendInviteEmails + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [InviteUsers]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): InviteUsers = InviteUsers( - ids?.toUnmodifiable(), - emails?.toUnmodifiable(), - sendInviteEmails, - groupIds?.toUnmodifiable(), - groupNames?.toUnmodifiable(), + (emails ?: JsonMissing.of()).map { it.toImmutable() }, groupId, + (groupIds ?: JsonMissing.of()).map { it.toImmutable() }, groupName, - additionalProperties.toUnmodifiable(), + (groupNames ?: JsonMissing.of()).map { it.toImmutable() }, + (ids ?: JsonMissing.of()).map { it.toImmutable() }, + sendInviteEmails, + additionalProperties.toMutableMap(), ) } - } - - /** Users to remove from the organization */ - @JsonDeserialize(builder = RemoveUsers.Builder::class) - @NoAutoDetect - class RemoveUsers - private constructor( - private val ids: List?, - private val emails: List?, - private val additionalProperties: Map, - ) { - private var hashCode: Int = 0 + private var validated: Boolean = false - /** Ids of users to remove */ - @JsonProperty("ids") fun ids(): List? = ids + fun validate(): InviteUsers = apply { + if (validated) { + return@apply + } - /** Emails of users to remove */ - @JsonProperty("emails") fun emails(): List? = emails + emails() + groupId() + groupIds() + groupName() + groupNames() + ids() + sendInviteEmails() + validated = true + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (emails.asKnown()?.size ?: 0) + + (if (groupId.asKnown() == null) 0 else 1) + + (groupIds.asKnown()?.size ?: 0) + + (if (groupName.asKnown() == null) 0 else 1) + + (groupNames.asKnown()?.size ?: 0) + + (ids.asKnown()?.size ?: 0) + + (if (sendInviteEmails.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is RemoveUsers && - this.ids == other.ids && - this.emails == other.emails && - this.additionalProperties == other.additionalProperties + return other is InviteUsers && + emails == other.emails && + groupId == other.groupId && + groupIds == other.groupIds && + groupName == other.groupName && + groupNames == other.groupNames && + ids == other.ids && + sendInviteEmails == other.sendInviteEmails && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - ids, - emails, - additionalProperties, - ) - } - return hashCode + private val hashCode: Int by lazy { + Objects.hash( + emails, + groupId, + groupIds, + groupName, + groupNames, + ids, + sendInviteEmails, + additionalProperties, + ) } + override fun hashCode(): Int = hashCode + override fun toString() = - "RemoveUsers{ids=$ids, emails=$emails, additionalProperties=$additionalProperties}" + "InviteUsers{emails=$emails, groupId=$groupId, groupIds=$groupIds, groupName=$groupName, groupNames=$groupNames, ids=$ids, sendInviteEmails=$sendInviteEmails, additionalProperties=$additionalProperties}" + } + + /** Users to remove from the organization */ + class RemoveUsers + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val emails: JsonField>, + private val ids: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("emails") + @ExcludeMissing + emails: JsonField> = JsonMissing.of(), + @JsonProperty("ids") @ExcludeMissing ids: JsonField> = JsonMissing.of(), + ) : this(emails, ids, mutableMapOf()) + + /** + * Emails of users to remove + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun emails(): List? = emails.getNullable("emails") + + /** + * Ids of users to remove + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun ids(): List? = ids.getNullable("ids") + + /** + * Returns the raw JSON value of [emails]. + * + * Unlike [emails], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("emails") @ExcludeMissing fun _emails(): JsonField> = emails + + /** + * Returns the raw JSON value of [ids]. + * + * Unlike [ids], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("ids") @ExcludeMissing fun _ids(): JsonField> = ids + + @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 [RemoveUsers]. */ fun builder() = Builder() } - class Builder { + /** A builder for [RemoveUsers]. */ + class Builder internal constructor() { - private var ids: List? = null - private var emails: List? = null + private var emails: JsonField>? = null + private var ids: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(removeUsers: RemoveUsers) = apply { - this.ids = removeUsers.ids - this.emails = removeUsers.emails - additionalProperties(removeUsers.additionalProperties) + emails = removeUsers.emails.map { it.toMutableList() } + ids = removeUsers.ids.map { it.toMutableList() } + additionalProperties = removeUsers.additionalProperties.toMutableMap() + } + + /** Emails of users to remove */ + fun emails(emails: List?) = emails(JsonField.ofNullable(emails)) + + /** + * Sets [Builder.emails] to an arbitrary JSON value. + * + * You should usually call [Builder.emails] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun emails(emails: JsonField>) = apply { + this.emails = emails.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [emails]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEmail(email: String) = apply { + emails = + (emails ?: JsonField.of(mutableListOf())).also { + checkKnown("emails", it).add(email) + } } /** Ids of users to remove */ - @JsonProperty("ids") fun ids(ids: List) = apply { this.ids = ids } + fun ids(ids: List?) = ids(JsonField.ofNullable(ids)) - /** Emails of users to remove */ - @JsonProperty("emails") - fun emails(emails: List) = apply { this.emails = emails } + /** + * Sets [Builder.ids] to an arbitrary JSON value. + * + * You should usually call [Builder.ids] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun ids(ids: JsonField>) = apply { + this.ids = ids.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [ids]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addId(id: String) = apply { + ids = (ids ?: JsonField.of(mutableListOf())).also { checkKnown("ids", it).add(id) } + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RemoveUsers]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): RemoveUsers = RemoveUsers( - ids?.toUnmodifiable(), - emails?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), + (emails ?: JsonMissing.of()).map { it.toImmutable() }, + (ids ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): RemoveUsers = apply { + if (validated) { + return@apply + } + + emails() + ids() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (emails.asKnown()?.size ?: 0) + (ids.asKnown()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RemoveUsers && + emails == other.emails && + ids == other.ids && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(emails, ids, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RemoveUsers{emails=$emails, ids=$ids, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is OrganizationMemberUpdateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "OrganizationMemberUpdateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParams.kt index a49d188c..e74686d8 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParams.kt @@ -2,125 +2,191 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get an organization object by its id */ class OrganizationRetrieveParams -constructor( - private val organizationId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val organizationId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun organizationId(): String = organizationId + /** Organization id */ + fun organizationId(): String? = organizationId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> organizationId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): OrganizationRetrieveParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [OrganizationRetrieveParams]. + */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [OrganizationRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var organizationId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(organizationRetrieveParams: OrganizationRetrieveParams) = apply { + organizationId = organizationRetrieveParams.organizationId + additionalHeaders = organizationRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = organizationRetrieveParams.additionalQueryParams.toBuilder() } - return other is OrganizationRetrieveParams && - this.organizationId == other.organizationId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Organization id */ + fun organizationId(organizationId: String?) = apply { this.organizationId = organizationId } - override fun hashCode(): Int { - return Objects.hash( - organizationId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "OrganizationRetrieveParams{organizationId=$organizationId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var organizationId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(organizationRetrieveParams: OrganizationRetrieveParams) = apply { - this.organizationId = organizationRetrieveParams.organizationId - additionalQueryParams(organizationRetrieveParams.additionalQueryParams) - additionalHeaders(organizationRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Organization id */ - fun organizationId(organizationId: String) = apply { this.organizationId = organizationId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [OrganizationRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): OrganizationRetrieveParams = OrganizationRetrieveParams( - checkNotNull(organizationId) { "`organizationId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + organizationId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> organizationId ?: "" + 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 OrganizationRetrieveParams && + organizationId == other.organizationId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(organizationId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "OrganizationRetrieveParams{organizationId=$organizationId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationUpdateParams.kt index 2debad5b..27f5122a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/OrganizationUpdateParams.kt @@ -3,342 +3,671 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update an organization object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ class OrganizationUpdateParams -constructor( - private val organizationId: String, - private val apiUrl: String?, - private val isUniversalApi: Boolean?, - private val name: String?, - private val proxyUrl: String?, - private val realtimeUrl: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun organizationId(): String = organizationId - - fun apiUrl(): String? = apiUrl - - fun isUniversalApi(): Boolean? = isUniversalApi - - fun name(): String? = name - - fun proxyUrl(): String? = proxyUrl - - fun realtimeUrl(): String? = realtimeUrl - - internal fun getBody(): OrganizationUpdateBody { - return OrganizationUpdateBody( - apiUrl, - isUniversalApi, - name, - proxyUrl, - realtimeUrl, - additionalBodyProperties, - ) - } +private constructor( + private val organizationId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Organization id */ + fun organizationId(): String? = organizationId + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun apiUrl(): String? = body.apiUrl() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun isUniversalApi(): Boolean? = body.isUniversalApi() + + /** + * Name of the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun proxyUrl(): String? = body.proxyUrl() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun realtimeUrl(): String? = body.realtimeUrl() + + /** + * Returns the raw JSON value of [apiUrl]. + * + * Unlike [apiUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _apiUrl(): JsonField = body._apiUrl() + + /** + * Returns the raw JSON value of [isUniversalApi]. + * + * Unlike [isUniversalApi], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _isUniversalApi(): JsonField = body._isUniversalApi() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [proxyUrl]. + * + * Unlike [proxyUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _proxyUrl(): JsonField = body._proxyUrl() + + /** + * Returns the raw JSON value of [realtimeUrl]. + * + * Unlike [realtimeUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _realtimeUrl(): JsonField = body._realtimeUrl() + + 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) - internal fun getQueryParams(): Map> = additionalQueryParams + companion object { - internal fun getHeaders(): Map> = additionalHeaders + fun none(): OrganizationUpdateParams = builder().build() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> organizationId - else -> "" - } + /** Returns a mutable builder for constructing an instance of [OrganizationUpdateParams]. */ + fun builder() = Builder() } - @JsonDeserialize(builder = OrganizationUpdateBody.Builder::class) - @NoAutoDetect - class OrganizationUpdateBody - internal constructor( - private val apiUrl: String?, - private val isUniversalApi: Boolean?, - private val name: String?, - private val proxyUrl: String?, - private val realtimeUrl: String?, - private val additionalProperties: Map, - ) { + /** A builder for [OrganizationUpdateParams]. */ + class Builder internal constructor() { - private var hashCode: Int = 0 + private var organizationId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonProperty("api_url") fun apiUrl(): String? = apiUrl + internal fun from(organizationUpdateParams: OrganizationUpdateParams) = apply { + organizationId = organizationUpdateParams.organizationId + body = organizationUpdateParams.body.toBuilder() + additionalHeaders = organizationUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = organizationUpdateParams.additionalQueryParams.toBuilder() + } - @JsonProperty("is_universal_api") fun isUniversalApi(): Boolean? = isUniversalApi + /** Organization id */ + fun organizationId(organizationId: String?) = apply { this.organizationId = organizationId } + + /** + * 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: + * - [apiUrl] + * - [isUniversalApi] + * - [name] + * - [proxyUrl] + * - [realtimeUrl] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + fun apiUrl(apiUrl: String?) = apply { body.apiUrl(apiUrl) } + + /** + * Sets [Builder.apiUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.apiUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun apiUrl(apiUrl: JsonField) = apply { body.apiUrl(apiUrl) } + + fun isUniversalApi(isUniversalApi: Boolean?) = apply { body.isUniversalApi(isUniversalApi) } + + /** + * Alias for [Builder.isUniversalApi]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun isUniversalApi(isUniversalApi: Boolean) = isUniversalApi(isUniversalApi as Boolean?) + + /** + * Sets [Builder.isUniversalApi] to an arbitrary JSON value. + * + * You should usually call [Builder.isUniversalApi] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isUniversalApi(isUniversalApi: JsonField) = apply { + body.isUniversalApi(isUniversalApi) + } /** Name of the organization */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + fun proxyUrl(proxyUrl: String?) = apply { body.proxyUrl(proxyUrl) } + + /** + * Sets [Builder.proxyUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.proxyUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun proxyUrl(proxyUrl: JsonField) = apply { body.proxyUrl(proxyUrl) } + + fun realtimeUrl(realtimeUrl: String?) = apply { body.realtimeUrl(realtimeUrl) } + + /** + * Sets [Builder.realtimeUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.realtimeUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun realtimeUrl(realtimeUrl: JsonField) = apply { body.realtimeUrl(realtimeUrl) } - @JsonProperty("proxy_url") fun proxyUrl(): String? = proxyUrl + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - @JsonProperty("realtime_url") fun realtimeUrl(): String? = realtimeUrl + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } - return other is OrganizationUpdateBody && - this.apiUrl == other.apiUrl && - this.isUniversalApi == other.isUniversalApi && - this.name == other.name && - this.proxyUrl == other.proxyUrl && - this.realtimeUrl == other.realtimeUrl && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - apiUrl, - isUniversalApi, - name, - proxyUrl, - realtimeUrl, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "OrganizationUpdateBody{apiUrl=$apiUrl, isUniversalApi=$isUniversalApi, name=$name, proxyUrl=$proxyUrl, realtimeUrl=$realtimeUrl, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var apiUrl: String? = null - private var isUniversalApi: Boolean? = null - private var name: String? = null - private var proxyUrl: String? = null - private var realtimeUrl: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(organizationUpdateBody: OrganizationUpdateBody) = apply { - this.apiUrl = organizationUpdateBody.apiUrl - this.isUniversalApi = organizationUpdateBody.isUniversalApi - this.name = organizationUpdateBody.name - this.proxyUrl = organizationUpdateBody.proxyUrl - this.realtimeUrl = organizationUpdateBody.realtimeUrl - additionalProperties(organizationUpdateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @JsonProperty("api_url") fun apiUrl(apiUrl: String) = apply { this.apiUrl = apiUrl } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - @JsonProperty("is_universal_api") - fun isUniversalApi(isUniversalApi: Boolean) = apply { - this.isUniversalApi = isUniversalApi - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Name of the organization */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("proxy_url") - fun proxyUrl(proxyUrl: String) = apply { this.proxyUrl = proxyUrl } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - @JsonProperty("realtime_url") - fun realtimeUrl(realtimeUrl: String) = apply { this.realtimeUrl = realtimeUrl } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): OrganizationUpdateBody = - OrganizationUpdateBody( - apiUrl, - isUniversalApi, - name, - proxyUrl, - realtimeUrl, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is OrganizationUpdateParams && - this.organizationId == other.organizationId && - this.apiUrl == other.apiUrl && - this.isUniversalApi == other.isUniversalApi && - this.name == other.name && - this.proxyUrl == other.proxyUrl && - this.realtimeUrl == other.realtimeUrl && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [OrganizationUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): OrganizationUpdateParams = + OrganizationUpdateParams( + organizationId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - organizationId, - apiUrl, - isUniversalApi, - name, - proxyUrl, - realtimeUrl, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "OrganizationUpdateParams{organizationId=$organizationId, apiUrl=$apiUrl, isUniversalApi=$isUniversalApi, name=$name, proxyUrl=$proxyUrl, realtimeUrl=$realtimeUrl, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun _pathParam(index: Int): String = + when (index) { + 0 -> organizationId ?: "" + else -> "" + } - fun toBuilder() = Builder().from(this) + override fun _headers(): Headers = additionalHeaders - companion object { + override fun _queryParams(): QueryParams = additionalQueryParams - fun builder() = Builder() - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val apiUrl: JsonField, + private val isUniversalApi: JsonField, + private val name: JsonField, + private val proxyUrl: JsonField, + private val realtimeUrl: JsonField, + private val additionalProperties: MutableMap, + ) { - @NoAutoDetect - class Builder { + @JsonCreator + private constructor( + @JsonProperty("api_url") @ExcludeMissing apiUrl: JsonField = JsonMissing.of(), + @JsonProperty("is_universal_api") + @ExcludeMissing + isUniversalApi: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("proxy_url") + @ExcludeMissing + proxyUrl: JsonField = JsonMissing.of(), + @JsonProperty("realtime_url") + @ExcludeMissing + realtimeUrl: JsonField = JsonMissing.of(), + ) : this(apiUrl, isUniversalApi, name, proxyUrl, realtimeUrl, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun apiUrl(): String? = apiUrl.getNullable("api_url") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun isUniversalApi(): Boolean? = isUniversalApi.getNullable("is_universal_api") + + /** + * Name of the organization + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun proxyUrl(): String? = proxyUrl.getNullable("proxy_url") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun realtimeUrl(): String? = realtimeUrl.getNullable("realtime_url") + + /** + * Returns the raw JSON value of [apiUrl]. + * + * Unlike [apiUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("api_url") @ExcludeMissing fun _apiUrl(): JsonField = apiUrl + + /** + * Returns the raw JSON value of [isUniversalApi]. + * + * Unlike [isUniversalApi], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("is_universal_api") + @ExcludeMissing + fun _isUniversalApi(): JsonField = isUniversalApi + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [proxyUrl]. + * + * Unlike [proxyUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("proxy_url") @ExcludeMissing fun _proxyUrl(): JsonField = proxyUrl + + /** + * Returns the raw JSON value of [realtimeUrl]. + * + * Unlike [realtimeUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("realtime_url") + @ExcludeMissing + fun _realtimeUrl(): JsonField = realtimeUrl - private var organizationId: String? = null - private var apiUrl: String? = null - private var isUniversalApi: Boolean? = null - private var name: String? = null - private var proxyUrl: String? = null - private var realtimeUrl: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - internal fun from(organizationUpdateParams: OrganizationUpdateParams) = apply { - this.organizationId = organizationUpdateParams.organizationId - this.apiUrl = organizationUpdateParams.apiUrl - this.isUniversalApi = organizationUpdateParams.isUniversalApi - this.name = organizationUpdateParams.name - this.proxyUrl = organizationUpdateParams.proxyUrl - this.realtimeUrl = organizationUpdateParams.realtimeUrl - additionalQueryParams(organizationUpdateParams.additionalQueryParams) - additionalHeaders(organizationUpdateParams.additionalHeaders) - additionalBodyProperties(organizationUpdateParams.additionalBodyProperties) + @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]. */ + fun builder() = Builder() } - /** Organization id */ - fun organizationId(organizationId: String) = apply { this.organizationId = organizationId } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun apiUrl(apiUrl: String) = apply { this.apiUrl = apiUrl } + private var apiUrl: JsonField = JsonMissing.of() + private var isUniversalApi: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var proxyUrl: JsonField = JsonMissing.of() + private var realtimeUrl: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun isUniversalApi(isUniversalApi: Boolean) = apply { this.isUniversalApi = isUniversalApi } + internal fun from(body: Body) = apply { + apiUrl = body.apiUrl + isUniversalApi = body.isUniversalApi + name = body.name + proxyUrl = body.proxyUrl + realtimeUrl = body.realtimeUrl + additionalProperties = body.additionalProperties.toMutableMap() + } - /** Name of the organization */ - fun name(name: String) = apply { this.name = name } + fun apiUrl(apiUrl: String?) = apiUrl(JsonField.ofNullable(apiUrl)) + + /** + * Sets [Builder.apiUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.apiUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun apiUrl(apiUrl: JsonField) = apply { this.apiUrl = apiUrl } + + fun isUniversalApi(isUniversalApi: Boolean?) = + isUniversalApi(JsonField.ofNullable(isUniversalApi)) + + /** + * Alias for [Builder.isUniversalApi]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun isUniversalApi(isUniversalApi: Boolean) = isUniversalApi(isUniversalApi as Boolean?) + + /** + * Sets [Builder.isUniversalApi] to an arbitrary JSON value. + * + * You should usually call [Builder.isUniversalApi] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isUniversalApi(isUniversalApi: JsonField) = apply { + this.isUniversalApi = isUniversalApi + } - fun proxyUrl(proxyUrl: String) = apply { this.proxyUrl = proxyUrl } + /** Name of the organization */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun proxyUrl(proxyUrl: String?) = proxyUrl(JsonField.ofNullable(proxyUrl)) + + /** + * Sets [Builder.proxyUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.proxyUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun proxyUrl(proxyUrl: JsonField) = apply { this.proxyUrl = proxyUrl } + + fun realtimeUrl(realtimeUrl: String?) = realtimeUrl(JsonField.ofNullable(realtimeUrl)) + + /** + * Sets [Builder.realtimeUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.realtimeUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun realtimeUrl(realtimeUrl: JsonField) = apply { + this.realtimeUrl = realtimeUrl + } - fun realtimeUrl(realtimeUrl: String) = apply { this.realtimeUrl = realtimeUrl } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body( + apiUrl, + isUniversalApi, + name, + proxyUrl, + realtimeUrl, + additionalProperties.toMutableMap(), + ) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + private var validated: Boolean = false - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun validate(): Body = apply { + if (validated) { + return@apply + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + apiUrl() + isUniversalApi() + name() + proxyUrl() + realtimeUrl() + validated = true } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (apiUrl.asKnown() == null) 0 else 1) + + (if (isUniversalApi.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (proxyUrl.asKnown() == null) 0 else 1) + + (if (realtimeUrl.asKnown() == null) 0 else 1) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + apiUrl == other.apiUrl && + isUniversalApi == other.isUniversalApi && + name == other.name && + proxyUrl == other.proxyUrl && + realtimeUrl == other.realtimeUrl && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(apiUrl, isUniversalApi, name, proxyUrl, realtimeUrl, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): OrganizationUpdateParams = - OrganizationUpdateParams( - checkNotNull(organizationId) { "`organizationId` is required but was not set" }, - apiUrl, - isUniversalApi, - name, - proxyUrl, - realtimeUrl, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{apiUrl=$apiUrl, isUniversalApi=$isUniversalApi, name=$name, proxyUrl=$proxyUrl, realtimeUrl=$realtimeUrl, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is OrganizationUpdateParams && + organizationId == other.organizationId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(organizationId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "OrganizationUpdateParams{organizationId=$organizationId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutput.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutput.kt index cd87055d..fc87672e 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutput.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutput.kt @@ -7,194 +7,370 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = PatchOrganizationMembersOutput.Builder::class) -@NoAutoDetect class PatchOrganizationMembersOutput +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val orgId: JsonField, private val status: JsonField, private val sendEmailError: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("send_email_error") + @ExcludeMissing + sendEmailError: JsonField = JsonMissing.of(), + ) : this(orgId, status, sendEmailError, mutableMapOf()) - private var hashCode: Int = 0 + /** + * The id of the org that was modified. + * + * @throws BraintrustInvalidDataException 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 orgId(): String = orgId.getRequired("org_id") + /** + * @throws BraintrustInvalidDataException 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") /** * If invite emails failed to send for some reason, the patch operation will still complete, but * we will return an error message here + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun sendEmailError(): String? = sendEmailError.getNullable("send_email_error") - @JsonProperty("status") @ExcludeMissing fun _status() = status + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId /** - * If invite emails failed to send for some reason, the patch operation will still complete, but - * we will return an error message here + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("send_email_error") @ExcludeMissing fun _sendEmailError() = sendEmailError + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - @JsonAnyGetter + /** + * Returns the raw JSON value of [sendEmailError]. + * + * Unlike [sendEmailError], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("send_email_error") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _sendEmailError(): JsonField = sendEmailError - fun validate(): PatchOrganizationMembersOutput = apply { - if (!validated) { - status() - sendEmailError() - validated = true - } + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is PatchOrganizationMembersOutput && - this.status == other.status && - this.sendEmailError == other.sendEmailError && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - status, - sendEmailError, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "PatchOrganizationMembersOutput{status=$status, sendEmailError=$sendEmailError, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of + * [PatchOrganizationMembersOutput]. + * + * The following fields are required: + * ```kotlin + * .orgId() + * .status() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [PatchOrganizationMembersOutput]. */ + class Builder internal constructor() { - private var status: JsonField = JsonMissing.of() + private var orgId: JsonField? = null + private var status: JsonField? = null private var sendEmailError: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(patchOrganizationMembersOutput: PatchOrganizationMembersOutput) = apply { - this.status = patchOrganizationMembersOutput.status - this.sendEmailError = patchOrganizationMembersOutput.sendEmailError - additionalProperties(patchOrganizationMembersOutput.additionalProperties) + orgId = patchOrganizationMembersOutput.orgId + status = patchOrganizationMembersOutput.status + sendEmailError = patchOrganizationMembersOutput.sendEmailError + additionalProperties = + patchOrganizationMembersOutput.additionalProperties.toMutableMap() } + /** The id of the org that was modified. */ + fun orgId(orgId: String) = orgId(JsonField.of(orgId)) + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgId(orgId: JsonField) = apply { this.orgId = orgId } + fun status(status: Status) = status(JsonField.of(status)) - @JsonProperty("status") - @ExcludeMissing + /** + * 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 } /** * If invite emails failed to send for some reason, the patch operation will still complete, * but we will return an error message here */ - fun sendEmailError(sendEmailError: String) = sendEmailError(JsonField.of(sendEmailError)) + fun sendEmailError(sendEmailError: String?) = + sendEmailError(JsonField.ofNullable(sendEmailError)) /** - * If invite emails failed to send for some reason, the patch operation will still complete, - * but we will return an error message here + * Sets [Builder.sendEmailError] to an arbitrary JSON value. + * + * You should usually call [Builder.sendEmailError] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("send_email_error") - @ExcludeMissing fun sendEmailError(sendEmailError: JsonField) = apply { this.sendEmailError = sendEmailError } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [PatchOrganizationMembersOutput]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .orgId() + * .status() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): PatchOrganizationMembersOutput = PatchOrganizationMembersOutput( - status, + checkRequired("orgId", orgId), + checkRequired("status", status), sendEmailError, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Status - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): PatchOrganizationMembersOutput = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + orgId() + status().validate() + sendEmailError() + validated = true + } - return other is Status && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (orgId.asKnown() == null) 0 else 1) + + (status.asKnown()?.validity() ?: 0) + + (if (sendEmailError.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + 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 { - val SUCCESS = Status(JsonField.of("success")) + val SUCCESS = of("success") fun of(value: String) = Status(JsonField.of(value)) } + /** An enum containing [Status]'s known values. */ enum class Known { - SUCCESS, + SUCCESS } + /** + * 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 { SUCCESS, + /** 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) { SUCCESS -> Value.SUCCESS 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { SUCCESS -> Known.SUCCESS else -> throw BraintrustInvalidDataException("Unknown Status: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 PatchOrganizationMembersOutput && + orgId == other.orgId && + status == other.status && + sendEmailError == other.sendEmailError && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(orgId, status, sendEmailError, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PatchOrganizationMembersOutput{orgId=$orgId, status=$status, sendEmailError=$sendEmailError, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PathLookupFilter.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PathLookupFilter.kt deleted file mode 100755 index 80699a99..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PathLookupFilter.kt +++ /dev/null @@ -1,244 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.databind.annotation.JsonDeserialize -import java.util.Objects - -/** - * A path-lookup filter describes an equality comparison against a specific sub-field in the event - * row. For instance, if you wish to filter on the value of `c` in `{"input": {"a": {"b": {"c": - * "hello"}}}}`, pass `path=["input", "a", "b", "c"]` and `value="hello"` - */ -@JsonDeserialize(builder = PathLookupFilter.Builder::class) -@NoAutoDetect -class PathLookupFilter -private constructor( - private val type: JsonField, - private val path: JsonField>, - private val value: JsonValue, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Denotes the type of filter as a path-lookup filter */ - fun type(): Type = type.getRequired("type") - - /** - * List of fields describing the path to the value to be checked against. For instance, if you - * wish to filter on the value of `c` in `{"input": {"a": {"b": {"c": "hello"}}}}`, pass - * `path=["input", "a", "b", "c"]` - */ - fun path(): List = path.getRequired("path") - - /** - * The value to compare equality-wise against the event value at the specified `path`. The value - * must be a "primitive", that is, any JSON-serializable object except for objects and arrays. - * For instance, if you wish to filter on the value of "input.a.b.c" in the object `{"input": - * {"a": {"b": {"c": "hello"}}}}`, pass `value="hello"` - */ - fun value(): JsonValue = value - - /** Denotes the type of filter as a path-lookup filter */ - @JsonProperty("type") @ExcludeMissing fun _type() = type - - /** - * List of fields describing the path to the value to be checked against. For instance, if you - * wish to filter on the value of `c` in `{"input": {"a": {"b": {"c": "hello"}}}}`, pass - * `path=["input", "a", "b", "c"]` - */ - @JsonProperty("path") @ExcludeMissing fun _path() = path - - /** - * The value to compare equality-wise against the event value at the specified `path`. The value - * must be a "primitive", that is, any JSON-serializable object except for objects and arrays. - * For instance, if you wish to filter on the value of "input.a.b.c" in the object `{"input": - * {"a": {"b": {"c": "hello"}}}}`, pass `value="hello"` - */ - @JsonProperty("value") @ExcludeMissing fun _value() = value - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): PathLookupFilter = apply { - if (!validated) { - type() - path() - value() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is PathLookupFilter && - this.type == other.type && - this.path == other.path && - this.value == other.value && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - path, - value, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "PathLookupFilter{type=$type, path=$path, value=$value, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var type: JsonField = JsonMissing.of() - private var path: JsonField> = JsonMissing.of() - private var value: JsonValue = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(pathLookupFilter: PathLookupFilter) = apply { - this.type = pathLookupFilter.type - this.path = pathLookupFilter.path - this.value = pathLookupFilter.value - additionalProperties(pathLookupFilter.additionalProperties) - } - - /** Denotes the type of filter as a path-lookup filter */ - fun type(type: Type) = type(JsonField.of(type)) - - /** Denotes the type of filter as a path-lookup filter */ - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - /** - * List of fields describing the path to the value to be checked against. For instance, if - * you wish to filter on the value of `c` in `{"input": {"a": {"b": {"c": "hello"}}}}`, pass - * `path=["input", "a", "b", "c"]` - */ - fun path(path: List) = path(JsonField.of(path)) - - /** - * List of fields describing the path to the value to be checked against. For instance, if - * you wish to filter on the value of `c` in `{"input": {"a": {"b": {"c": "hello"}}}}`, pass - * `path=["input", "a", "b", "c"]` - */ - @JsonProperty("path") - @ExcludeMissing - fun path(path: JsonField>) = apply { this.path = path } - - /** - * The value to compare equality-wise against the event value at the specified `path`. The - * value must be a "primitive", that is, any JSON-serializable object except for objects and - * arrays. For instance, if you wish to filter on the value of "input.a.b.c" in the object - * `{"input": {"a": {"b": {"c": "hello"}}}}`, pass `value="hello"` - */ - @JsonProperty("value") - @ExcludeMissing - fun value(value: JsonValue) = apply { this.value = value } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): PathLookupFilter = - PathLookupFilter( - type, - path.map { it.toUnmodifiable() }, - value, - additionalProperties.toUnmodifiable(), - ) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val PATH_LOOKUP = Type(JsonField.of("path_lookup")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - PATH_LOOKUP, - } - - enum class Value { - PATH_LOOKUP, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - PATH_LOOKUP -> Value.PATH_LOOKUP - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - PATH_LOOKUP -> Known.PATH_LOOKUP - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Permission.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Permission.kt new file mode 100644 index 00000000..00c9dafa --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Permission.kt @@ -0,0 +1,172 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Enum +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.errors.BraintrustInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator + +/** + * Each permission permits a certain type of operation on an object in the system + * + * Permissions can be assigned to to objects on an individual basis, or grouped into roles + */ +class Permission @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 { + + val CREATE = of("create") + + val READ = of("read") + + val UPDATE = of("update") + + val DELETE = of("delete") + + val CREATE_ACLS = of("create_acls") + + val READ_ACLS = of("read_acls") + + val UPDATE_ACLS = of("update_acls") + + val DELETE_ACLS = of("delete_acls") + + fun of(value: String) = Permission(JsonField.of(value)) + } + + /** An enum containing [Permission]'s known values. */ + enum class Known { + CREATE, + READ, + UPDATE, + DELETE, + CREATE_ACLS, + READ_ACLS, + UPDATE_ACLS, + DELETE_ACLS, + } + + /** + * An enum containing [Permission]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Permission] 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 { + CREATE, + READ, + UPDATE, + DELETE, + CREATE_ACLS, + READ_ACLS, + UPDATE_ACLS, + DELETE_ACLS, + /** An enum member indicating that [Permission] 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) { + CREATE -> Value.CREATE + READ -> Value.READ + UPDATE -> Value.UPDATE + DELETE -> Value.DELETE + CREATE_ACLS -> Value.CREATE_ACLS + READ_ACLS -> Value.READ_ACLS + UPDATE_ACLS -> Value.UPDATE_ACLS + DELETE_ACLS -> Value.DELETE_ACLS + 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + CREATE -> Known.CREATE + READ -> Known.READ + UPDATE -> Known.UPDATE + DELETE -> Known.DELETE + CREATE_ACLS -> Known.CREATE_ACLS + READ_ACLS -> Known.READ_ACLS + UPDATE_ACLS -> Known.UPDATE_ACLS + DELETE_ACLS -> Known.DELETE_ACLS + else -> throw BraintrustInvalidDataException("Unknown Permission: $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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Permission = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + 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 Permission && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Project.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Project.kt index 8024dbb6..c473f4de 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Project.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Project.kt @@ -6,231 +6,387 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = Project.Builder::class) -@NoAutoDetect class Project +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val orgId: JsonField, private val name: JsonField, + private val orgId: JsonField, private val created: JsonField, private val deletedAt: JsonField, - private val userId: JsonField, private val settings: JsonField, - private val additionalProperties: Map, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the project */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("settings") + @ExcludeMissing + settings: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this(id, name, orgId, created, deletedAt, settings, userId, mutableMapOf()) + + /** + * Unique identifier for the project + * + * @throws BraintrustInvalidDataException 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") - /** Unique id for the organization that the project belongs under */ - fun orgId(): String = orgId.getRequired("org_id") - - /** Name of the project */ + /** + * Name of the project + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** Date of project creation */ + /** + * Unique id for the organization that the project belongs under + * + * @throws BraintrustInvalidDataException 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 orgId(): String = orgId.getRequired("org_id") + + /** + * Date of project creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** Date of project deletion, or null if the project is still active */ + /** + * Date of project deletion, or null if the project is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - /** Identifies the user who created the project */ - fun userId(): String? = userId.getNullable("user_id") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun settings(): ProjectSettings? = settings.getNullable("settings") - /** Unique identifier for the project */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Unique id for the organization that the project belongs under */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId - - /** Name of the project */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Date of project creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Date of project deletion, or null if the project is still active */ - @JsonProperty("deleted_at") @ExcludeMissing fun _deletedAt() = deletedAt - - /** Identifies the user who created the project */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + /** + * Identifies the user who created the project + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - @JsonProperty("settings") @ExcludeMissing fun _settings() = settings + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt + + /** + * Returns the raw JSON value of [settings]. + * + * Unlike [settings], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("settings") @ExcludeMissing fun _settings(): JsonField = settings + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Project = apply { - if (!validated) { - id() - orgId() - name() - created() - deletedAt() - userId() - settings()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Project && - this.id == other.id && - this.orgId == other.orgId && - this.name == other.name && - this.created == other.created && - this.deletedAt == other.deletedAt && - this.userId == other.userId && - this.settings == other.settings && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - orgId, - name, - created, - deletedAt, - userId, - settings, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Project{id=$id, orgId=$orgId, name=$name, created=$created, deletedAt=$deletedAt, userId=$userId, settings=$settings, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Project]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .orgId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Project]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var orgId: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var orgId: JsonField? = null private var created: JsonField = JsonMissing.of() private var deletedAt: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() private var settings: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(project: Project) = apply { - this.id = project.id - this.orgId = project.orgId - this.name = project.name - this.created = project.created - this.deletedAt = project.deletedAt - this.userId = project.userId - this.settings = project.settings - additionalProperties(project.additionalProperties) + id = project.id + name = project.name + orgId = project.orgId + created = project.created + deletedAt = project.deletedAt + settings = project.settings + userId = project.userId + additionalProperties = project.additionalProperties.toMutableMap() } /** Unique identifier for the project */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the project */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** Unique id for the organization that the project belongs under */ - fun orgId(orgId: String) = orgId(JsonField.of(orgId)) - - /** Unique id for the organization that the project belongs under */ - @JsonProperty("org_id") - @ExcludeMissing - fun orgId(orgId: JsonField) = apply { this.orgId = orgId } + /** + * 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 } /** Name of the project */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the project */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } - /** Date of project creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** Unique id for the organization that the project belongs under */ + fun orgId(orgId: String) = orgId(JsonField.of(orgId)) + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgId(orgId: JsonField) = apply { this.orgId = orgId } /** Date of project creation */ - @JsonProperty("created") - @ExcludeMissing + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } /** Date of project deletion, or null if the project is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = deletedAt(JsonField.of(deletedAt)) - - /** Date of project deletion, or null if the project is still active */ - @JsonProperty("deleted_at") - @ExcludeMissing + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } - /** Identifies the user who created the project */ - fun userId(userId: String) = userId(JsonField.of(userId)) + fun settings(settings: ProjectSettings?) = settings(JsonField.ofNullable(settings)) + + /** + * Sets [Builder.settings] to an arbitrary JSON value. + * + * You should usually call [Builder.settings] with a well-typed [ProjectSettings] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun settings(settings: JsonField) = apply { this.settings = settings } /** Identifies the user who created the project */ - @JsonProperty("user_id") - @ExcludeMissing + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun userId(userId: JsonField) = apply { this.userId = userId } - fun settings(settings: ProjectSettings) = settings(JsonField.of(settings)) - - @JsonProperty("settings") - @ExcludeMissing - fun settings(settings: JsonField) = apply { this.settings = settings } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Project]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .orgId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Project = Project( - id, - orgId, - name, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("orgId", orgId), created, deletedAt, - userId, settings, - additionalProperties.toUnmodifiable(), + userId, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): Project = apply { + if (validated) { + return@apply + } + + id() + name() + orgId() + created() + deletedAt() + settings()?.validate() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (settings.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Project && + id == other.id && + name == other.name && + orgId == other.orgId && + created == other.created && + deletedAt == other.deletedAt && + settings == other.settings && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, name, orgId, created, deletedAt, settings, userId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Project{id=$id, name=$name, orgId=$orgId, created=$created, deletedAt=$deletedAt, settings=$settings, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectCreateParams.kt index 80cddd02..42d50b13 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectCreateParams.kt @@ -3,272 +3,487 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new project. If there is an existing project with the same name as the one specified in + * the request, will return the existing project unmodified + */ class ProjectCreateParams -constructor( - private val name: String, - private val orgName: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun orgName(): String? = orgName - - internal fun getBody(): ProjectCreateBody { - return ProjectCreateBody( - name, - orgName, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the project + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * project belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + 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 [ProjectCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = ProjectCreateBody.Builder::class) - @NoAutoDetect - class ProjectCreateBody - internal constructor( - private val name: String?, - private val orgName: String?, - private val additionalProperties: Map, - ) { + internal fun from(projectCreateParams: ProjectCreateParams) = apply { + body = projectCreateParams.body.toBuilder() + additionalHeaders = projectCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = projectCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [orgName] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the project */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the project belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ProjectCreateBody && - this.name == other.name && - this.orgName == other.orgName && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - orgName, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "ProjectCreateBody{name=$name, orgName=$orgName, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var name: String? = null - private var orgName: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectCreateBody: ProjectCreateBody) = apply { - this.name = projectCreateBody.name - this.orgName = projectCreateBody.orgName - additionalProperties(projectCreateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the project */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the project belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun build(): ProjectCreateBody = - ProjectCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - orgName, - additionalProperties.toUnmodifiable(), - ) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - return other is ProjectCreateParams && - this.name == other.name && - this.orgName == other.orgName && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun hashCode(): Int { - return Objects.hash( - name, - orgName, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - override fun toString() = - "ProjectCreateParams{name=$name, orgName=$orgName, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun toBuilder() = Builder().from(this) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - companion object { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun builder() = Builder() + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [ProjectCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectCreateParams = + ProjectCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var orgName: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(projectCreateParams: ProjectCreateParams) = apply { - this.name = projectCreateParams.name - this.orgName = projectCreateParams.orgName - additionalQueryParams(projectCreateParams.additionalQueryParams) - additionalHeaders(projectCreateParams.additionalHeaders) - additionalBodyProperties(projectCreateParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the project */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val orgName: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + ) : this(name, orgName, mutableMapOf()) + + /** + * Name of the project + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the project belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun toBuilder() = Builder().from(this) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + companion object { - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + private var name: JsonField? = null + private var orgName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + internal fun from(body: Body) = apply { + name = body.name + orgName = body.orgName + additionalProperties = body.additionalProperties.toMutableMap() + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Name of the project */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the project belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body(checkRequired("name", name), orgName, additionalProperties.toMutableMap()) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + orgName() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ProjectCreateParams = - ProjectCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - orgName, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (if (orgName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + orgName == other.orgName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, orgName, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, orgName=$orgName, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectDeleteParams.kt index ddf9a87e..1c53ef99 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a project object by its id */ class ProjectDeleteParams -constructor( - private val projectId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val projectId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun projectId(): String = projectId + /** Project id */ + fun projectId(): String? = projectId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ProjectDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var projectId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(projectDeleteParams: ProjectDeleteParams) = apply { + projectId = projectDeleteParams.projectId + additionalHeaders = projectDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = projectDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = projectDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Project id */ + fun projectId(projectId: String?) = apply { this.projectId = projectId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ProjectDeleteParams && - this.projectId == other.projectId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - projectId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "ProjectDeleteParams{projectId=$projectId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var projectId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(projectDeleteParams: ProjectDeleteParams) = apply { - this.projectId = projectDeleteParams.projectId - additionalQueryParams(projectDeleteParams.additionalQueryParams) - additionalHeaders(projectDeleteParams.additionalHeaders) - additionalBodyProperties(projectDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [ProjectDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectDeleteParams = ProjectDeleteParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + projectId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectId ?: "" + 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 ProjectDeleteParams && + projectId == other.projectId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(projectId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "ProjectDeleteParams{projectId=$projectId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPage.kt index 8bf90957..ae189ffa 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPage.kt @@ -2,172 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.ProjectService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see ProjectService.list */ class ProjectListPage private constructor( - private val projectsService: ProjectService, + private val service: ProjectService, private val params: ProjectListParams, - private val response: Response, -) { + private val response: ProjectListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [ProjectListPageResponse], but gracefully handles missing data. + * + * @see ProjectListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectListPage && - this.projectsService == other.projectsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - projectsService, - params, - response, - ) - } - - override fun toString() = - "ProjectListPage{projectsService=$projectsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ProjectListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ProjectListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ProjectListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ProjectListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): ProjectListPage? { - return getNextPageParams()?.let { projectsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(projectsService: ProjectService, params: ProjectListParams, response: Response) = - ProjectListPage( - projectsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): ProjectListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ProjectListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ProjectListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ProjectListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ProjectListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ProjectService? = null + private var params: ProjectListParams? = null + private var response: ProjectListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(projectListPage: ProjectListPage) = apply { + service = projectListPage.service + params = projectListPage.params + response = projectListPage.response } - override fun toString() = - "ProjectListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ProjectService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ProjectListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ProjectListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ProjectListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectListPage = + ProjectListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ProjectListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ProjectListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ProjectListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPageAsync.kt index f3ec0173..a7743f0b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPageAsync.kt @@ -2,178 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.ProjectServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see ProjectServiceAsync.list */ class ProjectListPageAsync private constructor( - private val projectsService: ProjectServiceAsync, + private val service: ProjectServiceAsync, private val params: ProjectListParams, - private val response: Response, -) { + private val response: ProjectListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [ProjectListPageResponse], but gracefully handles missing data. + * + * @see ProjectListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectListPageAsync && - this.projectsService == other.projectsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - projectsService, - params, - response, - ) - } - - override fun toString() = - "ProjectListPageAsync{projectsService=$projectsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ProjectListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ProjectListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ProjectListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ProjectListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): ProjectListPageAsync? { - return getNextPageParams()?.let { projectsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - projectsService: ProjectServiceAsync, - params: ProjectListParams, - response: Response - ) = - ProjectListPageAsync( - projectsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): ProjectListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ProjectListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ProjectListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ProjectListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ProjectListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ProjectServiceAsync? = null + private var params: ProjectListParams? = null + private var response: ProjectListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(projectListPageAsync: ProjectListPageAsync) = apply { + service = projectListPageAsync.service + params = projectListPageAsync.params + response = projectListPageAsync.response } - override fun toString() = - "ProjectListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ProjectServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ProjectListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ProjectListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ProjectListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectListPageAsync = + ProjectListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ProjectListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ProjectListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ProjectListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPageResponse.kt new file mode 100644 index 00000000..2f8d7c06 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 ProjectListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of project objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [ProjectListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ProjectListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(projectListPageResponse: ProjectListPageResponse) = apply { + objects = projectListPageResponse.objects.map { it.toMutableList() } + additionalProperties = projectListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of project objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Project] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Project) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [ProjectListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectListPageResponse = + ProjectListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ProjectListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListParams.kt index aeb9012f..3475531f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectListParams.kt @@ -2,106 +2,80 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all projects. The projects are sorted by creation date, with the most recently-created + * projects coming first + */ class ProjectListParams -constructor( +private constructor( private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, private val orgName: String?, private val projectName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Name of the project to search for */ fun projectName(): String? = projectName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.projectName?.let { params.put("project_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectListParams && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.projectName == other.projectName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - ids, - limit, - orgName, - projectName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "ProjectListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectName=$projectName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ProjectListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ProjectListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var ids: Ids? = null @@ -109,18 +83,18 @@ constructor( private var orgName: String? = null private var projectName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(projectListParams: ProjectListParams) = apply { - this.endingBefore = projectListParams.endingBefore - this.ids = projectListParams.ids - this.limit = projectListParams.limit - this.orgName = projectListParams.orgName - this.projectName = projectListParams.projectName - this.startingAfter = projectListParams.startingAfter - additionalQueryParams(projectListParams.additionalQueryParams) - additionalHeaders(projectListParams.additionalHeaders) + endingBefore = projectListParams.endingBefore + ids = projectListParams.ids + limit = projectListParams.limit + orgName = projectListParams.orgName + projectName = projectListParams.projectName + startingAfter = projectListParams.startingAfter + additionalHeaders = projectListParams.additionalHeaders.toBuilder() + additionalQueryParams = projectListParams.additionalQueryParams.toBuilder() } /** @@ -130,34 +104,35 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Name of the project to search for */ - fun projectName(projectName: String) = apply { this.projectName = projectName } + fun projectName(projectName: String?) = apply { this.projectName = projectName } /** * Pagination cursor id. @@ -166,48 +141,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ProjectListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectListParams = ProjectListParams( endingBefore, @@ -216,22 +254,46 @@ constructor( orgName, projectName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + projectName?.let { put("project_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -244,93 +306,74 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) + else -> throw IllegalStateException("Invalid Ids") } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true - } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is ProjectListParams && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + projectName == other.projectName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + ids, + limit, + orgName, + projectName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ProjectListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectName=$projectName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParams.kt index 6410fe8c..135f3eee 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParams.kt @@ -3,257 +3,462 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** Log feedback for a set of project logs events */ class ProjectLogFeedbackParams -constructor( - private val projectId: String, - private val feedback: List, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val projectId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Project id */ + fun projectId(): String? = projectId + + /** + * A list of project logs feedback items + * + * @throws BraintrustInvalidDataException 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 feedback(): List = body.feedback() + + /** + * Returns the raw JSON value of [feedback]. + * + * Unlike [feedback], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _feedback(): JsonField> = body._feedback() + + 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 projectId(): String = projectId + fun toBuilder() = Builder().from(this) - fun feedback(): List = feedback + companion object { - internal fun getBody(): ProjectLogFeedbackBody { - return ProjectLogFeedbackBody(feedback, additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [ProjectLogFeedbackParams]. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectLogFeedbackParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var projectId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectId - else -> "" + internal fun from(projectLogFeedbackParams: ProjectLogFeedbackParams) = apply { + projectId = projectLogFeedbackParams.projectId + body = projectLogFeedbackParams.body.toBuilder() + additionalHeaders = projectLogFeedbackParams.additionalHeaders.toBuilder() + additionalQueryParams = projectLogFeedbackParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ProjectLogFeedbackBody.Builder::class) - @NoAutoDetect - class ProjectLogFeedbackBody - internal constructor( - private val feedback: List?, - private val additionalProperties: Map, - ) { + /** Project id */ + fun projectId(projectId: String?) = apply { this.projectId = projectId } - private var hashCode: Int = 0 + /** + * 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: + * - [feedback] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** A list of project logs feedback items */ - @JsonProperty("feedback") fun feedback(): List? = feedback + fun feedback(feedback: List) = apply { body.feedback(feedback) } + + /** + * Sets [Builder.feedback] to an arbitrary JSON value. + * + * You should usually call [Builder.feedback] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun feedback(feedback: JsonField>) = apply { + body.feedback(feedback) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Adds a single [FeedbackProjectLogsItem] to [Builder.feedback]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFeedback(feedback: FeedbackProjectLogsItem) = apply { body.addFeedback(feedback) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ProjectLogFeedbackBody && - this.feedback == other.feedback && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(feedback, additionalProperties) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "ProjectLogFeedbackBody{feedback=$feedback, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var feedback: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectLogFeedbackBody: ProjectLogFeedbackBody) = apply { - this.feedback = projectLogFeedbackBody.feedback - additionalProperties(projectLogFeedbackBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** A list of project logs feedback items */ - @JsonProperty("feedback") - fun feedback(feedback: List) = apply { - this.feedback = feedback - } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun build(): ProjectLogFeedbackBody = - ProjectLogFeedbackBody( - checkNotNull(feedback) { "`feedback` is required but was not set" } - .toUnmodifiable(), - additionalProperties.toUnmodifiable() - ) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - return other is ProjectLogFeedbackParams && - this.projectId == other.projectId && - this.feedback == other.feedback && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - projectId, - feedback, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun toString() = - "ProjectLogFeedbackParams{projectId=$projectId, feedback=$feedback, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - companion object { + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun builder() = Builder() - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - @NoAutoDetect - class Builder { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - private var projectId: String? = null - private var feedback: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - internal fun from(projectLogFeedbackParams: ProjectLogFeedbackParams) = apply { - this.projectId = projectLogFeedbackParams.projectId - this.feedback(projectLogFeedbackParams.feedback) - additionalQueryParams(projectLogFeedbackParams.additionalQueryParams) - additionalHeaders(projectLogFeedbackParams.additionalHeaders) - additionalBodyProperties(projectLogFeedbackParams.additionalBodyProperties) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + /** + * Returns an immutable instance of [ProjectLogFeedbackParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectLogFeedbackParams = + ProjectLogFeedbackParams( + projectId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } - /** A list of project logs feedback items */ - fun feedback(feedback: List) = apply { - this.feedback.clear() - this.feedback.addAll(feedback) + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectId ?: "" + else -> "" } - /** A list of project logs feedback items */ - fun addFeedback(feedback: FeedbackProjectLogsItem) = apply { this.feedback.add(feedback) } + override fun _headers(): Headers = additionalHeaders - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + override fun _queryParams(): QueryParams = additionalQueryParams - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val feedback: JsonField>, + private val additionalProperties: MutableMap, + ) { - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + @JsonCreator + private constructor( + @JsonProperty("feedback") + @ExcludeMissing + feedback: JsonField> = JsonMissing.of() + ) : this(feedback, mutableMapOf()) + + /** + * A list of project logs feedback items + * + * @throws BraintrustInvalidDataException 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 feedback(): List = feedback.getRequired("feedback") + + /** + * Returns the raw JSON value of [feedback]. + * + * Unlike [feedback], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("feedback") + @ExcludeMissing + fun _feedback(): JsonField> = feedback - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun toBuilder() = Builder().from(this) - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + companion object { - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .feedback() + * ``` + */ + fun builder() = Builder() } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + private var feedback: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + internal fun from(body: Body) = apply { + feedback = body.feedback.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** A list of project logs feedback items */ + fun feedback(feedback: List) = feedback(JsonField.of(feedback)) + + /** + * Sets [Builder.feedback] to an arbitrary JSON value. + * + * You should usually call [Builder.feedback] with a well-typed + * `List` value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun feedback(feedback: JsonField>) = apply { + this.feedback = feedback.map { it.toMutableList() } + } + + /** + * Adds a single [FeedbackProjectLogsItem] to [Builder.feedback]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFeedback(feedback: FeedbackProjectLogsItem) = apply { + this.feedback = + (this.feedback ?: JsonField.of(mutableListOf())).also { + checkKnown("feedback", it).add(feedback) + } + } + + 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: + * ```kotlin + * .feedback() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("feedback", feedback).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + feedback().forEach { it.validate() } + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ProjectLogFeedbackParams = - ProjectLogFeedbackParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(feedback) { "`feedback` is required but was not set" } - .toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (feedback.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + feedback == other.feedback && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(feedback, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{feedback=$feedback, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectLogFeedbackParams && + projectId == other.projectId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(projectId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectLogFeedbackParams{projectId=$projectId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchParams.kt index 76681e1c..5031625c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchParams.kt @@ -2,115 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** + * Fetch the events in a project logs. Equivalent to the POST form of the same path, but with the + * parameters in the URL query rather than in the request body. For more complex queries, use the + * `POST /btql` endpoint. + */ class ProjectLogFetchParams -constructor( - private val projectId: String, +private constructor( + private val projectId: String?, private val limit: Long?, private val maxRootSpanId: String?, private val maxXactId: String?, private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - - fun projectId(): String = projectId - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Project id */ + fun projectId(): String? = projectId + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, later + * pages may return rows which showed up in earlier pages, except with an earlier `_xact_id`. + * This happens because pagination occurs over the whole version history of the event log. You + * will most likely want to exclude any such duplicate, outdated rows (by `id`) from your + * combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up with + * more individual rows than the specified limit if you are fetching events containing traces. + */ fun limit(): Long? = limit + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + */ fun maxRootSpanId(): String? = maxRootSpanId + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + */ fun maxXactId(): String? = maxXactId + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use the + * `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + */ fun version(): String? = version - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.maxRootSpanId?.let { params.put("max_root_span_id", listOf(it.toString())) } - this.maxXactId?.let { params.put("max_xact_id", listOf(it.toString())) } - this.version?.let { params.put("version", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectId - else -> "" - } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - return other is ProjectLogFetchParams && - this.projectId == other.projectId && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - projectId, - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "ProjectLogFetchParams{projectId=$projectId, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ProjectLogFetchParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectLogFetchParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ProjectLogFetchParams]. */ + class Builder internal constructor() { private var projectId: String? = null private var limit: Long? = null private var maxRootSpanId: String? = null private var maxXactId: String? = null private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(projectLogFetchParams: ProjectLogFetchParams) = apply { - this.projectId = projectLogFetchParams.projectId - this.limit = projectLogFetchParams.limit - this.maxRootSpanId = projectLogFetchParams.maxRootSpanId - this.maxXactId = projectLogFetchParams.maxXactId - this.version = projectLogFetchParams.version - additionalQueryParams(projectLogFetchParams.additionalQueryParams) - additionalHeaders(projectLogFetchParams.additionalHeaders) + projectId = projectLogFetchParams.projectId + limit = projectLogFetchParams.limit + maxRootSpanId = projectLogFetchParams.maxRootSpanId + maxXactId = projectLogFetchParams.maxXactId + version = projectLogFetchParams.version + additionalHeaders = projectLogFetchParams.additionalHeaders.toBuilder() + additionalQueryParams = projectLogFetchParams.additionalQueryParams.toBuilder() } /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String?) = apply { this.projectId = projectId } /** * limit the number of traces fetched @@ -127,7 +133,14 @@ constructor( * with more individual rows than the specified limit if you are fetching events containing * traces. */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -141,7 +154,7 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } + fun maxRootSpanId(maxRootSpanId: String?) = apply { this.maxRootSpanId = maxRootSpanId } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -155,7 +168,7 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun maxXactId(maxXactId: String?) = apply { this.maxXactId = maxXactId } /** * Retrieve a snapshot of events from a past time @@ -163,57 +176,168 @@ constructor( * The version id is essentially a filter on the latest event transaction id. You can use * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. */ - fun version(version: String) = apply { this.version = version } + fun version(version: String?) = apply { this.version = version } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + 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 removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ProjectLogFetchParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectLogFetchParams = ProjectLogFetchParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, + projectId, limit, maxRootSpanId, maxXactId, version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + limit?.let { put("limit", it.toString()) } + maxRootSpanId?.let { put("max_root_span_id", it) } + maxXactId?.let { put("max_xact_id", it) } + version?.let { put("version", it) } + putAll(additionalQueryParams) + } + .build() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectLogFetchParams && + projectId == other.projectId && + limit == other.limit && + maxRootSpanId == other.maxRootSpanId && + maxXactId == other.maxXactId && + version == other.version && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + projectId, + limit, + maxRootSpanId, + maxXactId, + version, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ProjectLogFetchParams{projectId=$projectId, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParams.kt index 16c32c43..01756ad0 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParams.kt @@ -3,81 +3,197 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Fetch the events in a project logs. Equivalent to the GET form of the same path, but with the + * parameters in the request body rather than in the URL query. For more complex queries, use the + * `POST /btql` endpoint. + */ class ProjectLogFetchPostParams -constructor( - private val projectId: String, - private val cursor: String?, - private val filters: List?, - private val limit: Long?, - private val maxRootSpanId: String?, - private val maxXactId: String?, - private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun projectId(): String = projectId - - fun cursor(): String? = cursor - - fun filters(): List? = filters - - fun limit(): Long? = limit - - fun maxRootSpanId(): String? = maxRootSpanId - - fun maxXactId(): String? = maxXactId - - fun version(): String? = version - - internal fun getBody(): ProjectLogFetchPostBody { - return ProjectLogFetchPostBody( - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalBodyProperties, - ) +private constructor( + private val projectId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Project id */ + fun projectId(): String? = projectId + + /** + * An opaque string to be used as a cursor for the next page of results, in order from latest to + * earliest. + * + * The string can be obtained directly from the `cursor` property of the previous fetch query + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun cursor(): String? = body.cursor() + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, later + * pages may return rows which showed up in earlier pages, except with an earlier `_xact_id`. + * This happens because pagination occurs over the whole version history of the event log. You + * will most likely want to exclude any such duplicate, outdated rows (by `id`) from your + * combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up with + * more individual rows than the specified limit if you are fetching events containing traces. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun limit(): Long? = body.limit() + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun maxRootSpanId(): String? = body.maxRootSpanId() + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of the + * explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' argument + * going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the cursor + * for the next page can be found as the row with the minimum (earliest) value of the tuple + * `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of paginating + * fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun maxXactId(): String? = body.maxXactId() + + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use the + * `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun version(): String? = body.version() + + /** + * Returns the raw JSON value of [cursor]. + * + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _cursor(): JsonField = body._cursor() + + /** + * Returns the raw JSON value of [limit]. + * + * Unlike [limit], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _limit(): JsonField = body._limit() + + /** + * Returns the raw JSON value of [maxRootSpanId]. + * + * Unlike [maxRootSpanId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _maxRootSpanId(): JsonField = body._maxRootSpanId() + + /** + * Returns the raw JSON value of [maxXactId]. + * + * Unlike [maxXactId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _maxXactId(): JsonField = body._maxXactId() + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _version(): JsonField = body._version() + + 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 { + + fun none(): ProjectLogFetchPostParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [ProjectLogFetchPostParams]. + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectLogFetchPostParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var projectId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectId - else -> "" + internal fun from(projectLogFetchPostParams: ProjectLogFetchPostParams) = apply { + projectId = projectLogFetchPostParams.projectId + body = projectLogFetchPostParams.body.toBuilder() + additionalHeaders = projectLogFetchPostParams.additionalHeaders.toBuilder() + additionalQueryParams = projectLogFetchPostParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ProjectLogFetchPostBody.Builder::class) - @NoAutoDetect - class ProjectLogFetchPostBody - internal constructor( - private val cursor: String?, - private val filters: List?, - private val limit: Long?, - private val maxRootSpanId: String?, - private val maxXactId: String?, - private val version: String?, - private val additionalProperties: Map, - ) { + /** Project id */ + fun projectId(projectId: String?) = apply { this.projectId = projectId } - private var hashCode: Int = 0 + /** + * 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: + * - [cursor] + * - [limit] + * - [maxRootSpanId] + * - [maxXactId] + * - [version] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** * An opaque string to be used as a cursor for the next page of results, in order from @@ -86,17 +202,15 @@ constructor( * The string can be obtained directly from the `cursor` property of the previous fetch * query */ - @JsonProperty("cursor") fun cursor(): String? = cursor + fun cursor(cursor: String?) = apply { body.cursor(cursor) } /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. + * Sets [Builder.cursor] to an arbitrary JSON value. * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. + * You should usually call [Builder.cursor] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("filters") fun filters(): List? = filters + fun cursor(cursor: JsonField) = apply { body.cursor(cursor) } /** * limit the number of traces fetched @@ -113,7 +227,22 @@ constructor( * with more individual rows than the specified limit if you are fetching events containing * traces. */ - @JsonProperty("limit") fun limit(): Long? = limit + fun limit(limit: Long?) = apply { body.limit(limit) } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** + * Sets [Builder.limit] to an arbitrary JSON value. + * + * You should usually call [Builder.limit] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun limit(limit: JsonField) = apply { body.limit(limit) } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -127,7 +256,18 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - @JsonProperty("max_root_span_id") fun maxRootSpanId(): String? = maxRootSpanId + fun maxRootSpanId(maxRootSpanId: String?) = apply { body.maxRootSpanId(maxRootSpanId) } + + /** + * Sets [Builder.maxRootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxRootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun maxRootSpanId(maxRootSpanId: JsonField) = apply { + body.maxRootSpanId(maxRootSpanId) + } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of @@ -141,7 +281,16 @@ constructor( * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of * paginating fetch queries. */ - @JsonProperty("max_xact_id") fun maxXactId(): String? = maxXactId + fun maxXactId(maxXactId: String?) = apply { body.maxXactId(maxXactId) } + + /** + * Sets [Builder.maxXactId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxXactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun maxXactId(maxXactId: JsonField) = apply { body.maxXactId(maxXactId) } /** * Retrieve a snapshot of events from a past time @@ -149,71 +298,333 @@ constructor( * The version id is essentially a filter on the latest event transaction id. You can use * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. */ - @JsonProperty("version") fun version(): String? = version + fun version(version: String?) = apply { body.version(version) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun version(version: JsonField) = apply { body.version(version) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ProjectLogFetchPostBody && - this.cursor == other.cursor && - this.filters == other.filters && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalProperties, - ) + 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) } - return hashCode + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - override fun toString() = - "ProjectLogFetchPostBody{cursor=$cursor, filters=$filters, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalProperties=$additionalProperties}" + 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 [ProjectLogFetchPostParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ProjectLogFetchPostParams = + ProjectLogFetchPostParams( + projectId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cursor: JsonField, + private val limit: JsonField, + private val maxRootSpanId: JsonField, + private val maxXactId: JsonField, + private val version: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cursor") @ExcludeMissing cursor: JsonField = JsonMissing.of(), + @JsonProperty("limit") @ExcludeMissing limit: JsonField = JsonMissing.of(), + @JsonProperty("max_root_span_id") + @ExcludeMissing + maxRootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("max_xact_id") + @ExcludeMissing + maxXactId: JsonField = JsonMissing.of(), + @JsonProperty("version") @ExcludeMissing version: JsonField = JsonMissing.of(), + ) : this(cursor, limit, maxRootSpanId, maxXactId, version, mutableMapOf()) + + /** + * An opaque string to be used as a cursor for the next page of results, in order from + * latest to earliest. + * + * The string can be obtained directly from the `cursor` property of the previous fetch + * query + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cursor(): String? = cursor.getNullable("cursor") + + /** + * limit the number of traces fetched + * + * Fetch queries may be paginated if the total result size is expected to be large (e.g. + * project_logs which accumulate over a long time). Note that fetch queries only support + * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, + * later pages may return rows which showed up in earlier pages, except with an earlier + * `_xact_id`. This happens because pagination occurs over the whole version history of the + * event log. You will most likely want to exclude any such duplicate, outdated rows (by + * `id`) from your combined result set. + * + * The `limit` parameter controls the number of full traces to return. So you may end up + * with more individual rows than the specified limit if you are fetching events containing + * traces. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun limit(): Long? = limit.getNullable("limit") + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of + * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' + * argument going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the + * cursor for the next page can be found as the row with the minimum (earliest) value of the + * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of + * paginating fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxRootSpanId(): String? = maxRootSpanId.getNullable("max_root_span_id") + + /** + * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of + * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' + * argument going forwards. + * + * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor + * + * Since a paginated fetch query returns results in order from latest to earliest, the + * cursor for the next page can be found as the row with the minimum (earliest) value of the + * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of + * paginating fetch queries. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxXactId(): String? = maxXactId.getNullable("max_xact_id") + + /** + * Retrieve a snapshot of events from a past time + * + * The version id is essentially a filter on the latest event transaction id. You can use + * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun version(): String? = version.getNullable("version") + + /** + * Returns the raw JSON value of [cursor]. + * + * Unlike [cursor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cursor") @ExcludeMissing fun _cursor(): JsonField = cursor + + /** + * Returns the raw JSON value of [limit]. + * + * Unlike [limit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("limit") @ExcludeMissing fun _limit(): JsonField = limit + + /** + * Returns the raw JSON value of [maxRootSpanId]. + * + * Unlike [maxRootSpanId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("max_root_span_id") + @ExcludeMissing + fun _maxRootSpanId(): JsonField = maxRootSpanId + + /** + * Returns the raw JSON value of [maxXactId]. + * + * Unlike [maxXactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("max_xact_id") @ExcludeMissing fun _maxXactId(): JsonField = maxXactId + + /** + * Returns the raw JSON value of [version]. + * + * Unlike [version], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("version") @ExcludeMissing fun _version(): JsonField = version + + @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]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Body]. */ + class Builder internal constructor() { - private var cursor: String? = null - private var filters: List? = null - private var limit: Long? = null - private var maxRootSpanId: String? = null - private var maxXactId: String? = null - private var version: String? = null + private var cursor: JsonField = JsonMissing.of() + private var limit: JsonField = JsonMissing.of() + private var maxRootSpanId: JsonField = JsonMissing.of() + private var maxXactId: JsonField = JsonMissing.of() + private var version: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(projectLogFetchPostBody: ProjectLogFetchPostBody) = apply { - this.cursor = projectLogFetchPostBody.cursor - this.filters = projectLogFetchPostBody.filters - this.limit = projectLogFetchPostBody.limit - this.maxRootSpanId = projectLogFetchPostBody.maxRootSpanId - this.maxXactId = projectLogFetchPostBody.maxXactId - this.version = projectLogFetchPostBody.version - additionalProperties(projectLogFetchPostBody.additionalProperties) + internal fun from(body: Body) = apply { + cursor = body.cursor + limit = body.limit + maxRootSpanId = body.maxRootSpanId + maxXactId = body.maxXactId + version = body.version + additionalProperties = body.additionalProperties.toMutableMap() } /** @@ -223,18 +634,16 @@ constructor( * The string can be obtained directly from the `cursor` property of the previous fetch * query */ - @JsonProperty("cursor") fun cursor(cursor: String) = apply { this.cursor = cursor } + fun cursor(cursor: String?) = cursor(JsonField.ofNullable(cursor)) /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. + * Sets [Builder.cursor] to an arbitrary JSON value. * - * A list of filters on the events to fetch. Currently, only path-lookup type filters - * are supported. + * You should usually call [Builder.cursor] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("filters") - fun filters(filters: List) = apply { this.filters = filters } + fun cursor(cursor: JsonField) = apply { this.cursor = cursor } /** * limit the number of traces fetched @@ -251,7 +660,23 @@ constructor( * with more individual rows than the specified limit if you are fetching events * containing traces. */ - @JsonProperty("limit") fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = limit(JsonField.ofNullable(limit)) + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** + * Sets [Builder.limit] to an arbitrary JSON value. + * + * You should usually call [Builder.limit] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun limit(limit: JsonField) = apply { this.limit = limit } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor @@ -265,8 +690,19 @@ constructor( * the tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an * overview of paginating fetch queries. */ - @JsonProperty("max_root_span_id") - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } + fun maxRootSpanId(maxRootSpanId: String?) = + maxRootSpanId(JsonField.ofNullable(maxRootSpanId)) + + /** + * Sets [Builder.maxRootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxRootSpanId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxRootSpanId(maxRootSpanId: JsonField) = apply { + this.maxRootSpanId = maxRootSpanId + } /** * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor @@ -280,8 +716,16 @@ constructor( * the tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an * overview of paginating fetch queries. */ - @JsonProperty("max_xact_id") - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun maxXactId(maxXactId: String?) = maxXactId(JsonField.ofNullable(maxXactId)) + + /** + * Sets [Builder.maxXactId] to an arbitrary JSON value. + * + * You should usually call [Builder.maxXactId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxXactId(maxXactId: JsonField) = apply { this.maxXactId = maxXactId } /** * Retrieve a snapshot of events from a past time @@ -290,265 +734,127 @@ constructor( * use the `max_xact_id` returned by a past fetch as the version to reproduce that exact * fetch. */ - @JsonProperty("version") fun version(version: String) = apply { this.version = version } + fun version(version: String?) = version(JsonField.ofNullable(version)) + + /** + * Sets [Builder.version] to an arbitrary JSON value. + * + * You should usually call [Builder.version] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun version(version: JsonField) = apply { this.version = version } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): ProjectLogFetchPostBody = - ProjectLogFetchPostBody( + 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( cursor, - filters?.toUnmodifiable(), limit, maxRootSpanId, maxXactId, version, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectLogFetchPostParams && - this.projectId == other.projectId && - this.cursor == other.cursor && - this.filters == other.filters && - this.limit == other.limit && - this.maxRootSpanId == other.maxRootSpanId && - this.maxXactId == other.maxXactId && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int { - return Objects.hash( - projectId, - cursor, - filters, - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } - - override fun toString() = - "ProjectLogFetchPostParams{projectId=$projectId, cursor=$cursor, filters=$filters, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) - - companion object { - - fun builder() = Builder() - } - - @NoAutoDetect - class Builder { - - private var projectId: String? = null - private var cursor: String? = null - private var filters: MutableList = mutableListOf() - private var limit: Long? = null - private var maxRootSpanId: String? = null - private var maxXactId: String? = null - private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() - - internal fun from(projectLogFetchPostParams: ProjectLogFetchPostParams) = apply { - this.projectId = projectLogFetchPostParams.projectId - this.cursor = projectLogFetchPostParams.cursor - this.filters(projectLogFetchPostParams.filters ?: listOf()) - this.limit = projectLogFetchPostParams.limit - this.maxRootSpanId = projectLogFetchPostParams.maxRootSpanId - this.maxXactId = projectLogFetchPostParams.maxXactId - this.version = projectLogFetchPostParams.version - additionalQueryParams(projectLogFetchPostParams.additionalQueryParams) - additionalHeaders(projectLogFetchPostParams.additionalHeaders) - additionalBodyProperties(projectLogFetchPostParams.additionalBodyProperties) - } - /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var validated: Boolean = false - /** - * An opaque string to be used as a cursor for the next page of results, in order from - * latest to earliest. - * - * The string can be obtained directly from the `cursor` property of the previous fetch - * query - */ - fun cursor(cursor: String) = apply { this.cursor = cursor } + fun validate(): Body = apply { + if (validated) { + return@apply + } - /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. - * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. - */ - fun filters(filters: List) = apply { - this.filters.clear() - this.filters.addAll(filters) + cursor() + limit() + maxRootSpanId() + maxXactId() + version() + validated = true } - /** - * NOTE: This parameter is deprecated and will be removed in a future revision. Consider - * using the `/btql` endpoint (https://www.braintrust.dev/docs/reference/btql) for more - * advanced filtering. - * - * A list of filters on the events to fetch. Currently, only path-lookup type filters are - * supported. - */ - fun addFilter(filter: PathLookupFilter) = apply { this.filters.add(filter) } - - /** - * limit the number of traces fetched - * - * Fetch queries may be paginated if the total result size is expected to be large (e.g. - * project_logs which accumulate over a long time). Note that fetch queries only support - * pagination in descending time order (from latest to earliest `_xact_id`. Furthermore, - * later pages may return rows which showed up in earlier pages, except with an earlier - * `_xact_id`. This happens because pagination occurs over the whole version history of the - * event log. You will most likely want to exclude any such duplicate, outdated rows (by - * `id`) from your combined result set. - * - * The `limit` parameter controls the number of full traces to return. So you may end up - * with more individual rows than the specified limit if you are fetching events containing - * traces. - */ - fun limit(limit: Long) = apply { this.limit = limit } - - /** - * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of - * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' - * argument going forwards. - * - * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor - * - * Since a paginated fetch query returns results in order from latest to earliest, the - * cursor for the next page can be found as the row with the minimum (earliest) value of the - * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of - * paginating fetch queries. - */ - fun maxRootSpanId(maxRootSpanId: String) = apply { this.maxRootSpanId = maxRootSpanId } - - /** - * DEPRECATION NOTICE: The manually-constructed pagination cursor is deprecated in favor of - * the explicit 'cursor' returned by object fetch requests. Please prefer the 'cursor' - * argument going forwards. - * - * Together, `max_xact_id` and `max_root_span_id` form a pagination cursor - * - * Since a paginated fetch query returns results in order from latest to earliest, the - * cursor for the next page can be found as the row with the minimum (earliest) value of the - * tuple `(_xact_id, root_span_id)`. See the documentation of `limit` for an overview of - * paginating fetch queries. - */ - fun maxXactId(maxXactId: String) = apply { this.maxXactId = maxXactId } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } /** - * Retrieve a snapshot of events from a past time + * Returns a score indicating how many valid values are contained in this object + * recursively. * - * The version id is essentially a filter on the latest event transaction id. You can use - * the `max_xact_id` returned by a past fetch as the version to reproduce that exact fetch. + * Used for best match union deserialization. */ - fun version(version: String) = apply { this.version = version } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + internal fun validity(): Int = + (if (cursor.asKnown() == null) 0 else 1) + + (if (limit.asKnown() == null) 0 else 1) + + (if (maxRootSpanId.asKnown() == null) 0 else 1) + + (if (maxXactId.asKnown() == null) 0 else 1) + + (if (version.asKnown() == null) 0 else 1) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } - - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } - - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } - - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + return other is Body && + cursor == other.cursor && + limit == other.limit && + maxRootSpanId == other.maxRootSpanId && + maxXactId == other.maxXactId && + version == other.version && + additionalProperties == other.additionalProperties } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + private val hashCode: Int by lazy { + Objects.hash(cursor, limit, maxRootSpanId, maxXactId, version, additionalProperties) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + override fun hashCode(): Int = hashCode - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + override fun toString() = + "Body{cursor=$cursor, limit=$limit, maxRootSpanId=$maxRootSpanId, maxXactId=$maxXactId, version=$version, additionalProperties=$additionalProperties}" + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) - } + return other is ProjectLogFetchPostParams && + projectId == other.projectId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = + Objects.hash(projectId, body, additionalHeaders, additionalQueryParams) - fun build(): ProjectLogFetchPostParams = - ProjectLogFetchPostParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, - cursor, - if (filters.size == 0) null else filters.toUnmodifiable(), - limit, - maxRootSpanId, - maxXactId, - version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + override fun toString() = + "ProjectLogFetchPostParams{projectId=$projectId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogInsertParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogInsertParams.kt index e68df8d4..5d581ba1 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogInsertParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogInsertParams.kt @@ -2,405 +2,460 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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 +/** Insert a set of events into the project logs */ class ProjectLogInsertParams -constructor( - private val projectId: String, - private val events: List, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val projectId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Project id */ + fun projectId(): String? = projectId + + /** + * A list of project logs events to insert + * + * @throws BraintrustInvalidDataException 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 events(): List = body.events() + + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _events(): JsonField> = body._events() + + 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 projectId(): String = projectId + fun toBuilder() = Builder().from(this) - fun events(): List = events + companion object { - internal fun getBody(): ProjectLogInsertBody { - return ProjectLogInsertBody(events, additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [ProjectLogInsertParams]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectLogInsertParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var projectId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectId - else -> "" + internal fun from(projectLogInsertParams: ProjectLogInsertParams) = apply { + projectId = projectLogInsertParams.projectId + body = projectLogInsertParams.body.toBuilder() + additionalHeaders = projectLogInsertParams.additionalHeaders.toBuilder() + additionalQueryParams = projectLogInsertParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ProjectLogInsertBody.Builder::class) - @NoAutoDetect - class ProjectLogInsertBody - internal constructor( - private val events: List?, - private val additionalProperties: Map, - ) { + /** Project id */ + fun projectId(projectId: String?) = apply { this.projectId = projectId } - private var hashCode: Int = 0 + /** + * 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: + * - [events] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** A list of project logs events to insert */ - @JsonProperty("events") fun events(): List? = events - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun events(events: List) = apply { body.events(events) } + + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun events(events: JsonField>) = apply { body.events(events) } + + /** + * Adds a single [InsertProjectLogsEvent] to [events]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEvent(event: InsertProjectLogsEvent) = apply { body.addEvent(event) } - return other is ProjectLogInsertBody && - this.events == other.events && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(events, additionalProperties) - } - return hashCode + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) } - override fun toString() = - "ProjectLogInsertBody{events=$events, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - class Builder { - - private var events: List? = null - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(projectLogInsertBody: ProjectLogInsertBody) = apply { - this.events = projectLogInsertBody.events - additionalProperties(projectLogInsertBody.additionalProperties) - } - - /** A list of project logs events to insert */ - @JsonProperty("events") fun events(events: List) = apply { this.events = events } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - fun build(): ProjectLogInsertBody = - ProjectLogInsertBody( - checkNotNull(events) { "`events` is required but was not set" } - .toUnmodifiable(), - additionalProperties.toUnmodifiable() - ) + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ProjectLogInsertParams && - this.projectId == other.projectId && - this.events == other.events && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - projectId, - events, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "ProjectLogInsertParams{projectId=$projectId, events=$events, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var projectId: String? = null - private var events: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(projectLogInsertParams: ProjectLogInsertParams) = apply { - this.projectId = projectLogInsertParams.projectId - this.events(projectLogInsertParams.events) - additionalQueryParams(projectLogInsertParams.additionalQueryParams) - additionalHeaders(projectLogInsertParams.additionalHeaders) - additionalBodyProperties(projectLogInsertParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** A list of project logs events to insert */ - fun events(events: List) = apply { - this.events.clear() - this.events.addAll(events) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - /** A list of project logs events to insert */ - fun addEvent(event: Event) = apply { this.events.add(event) } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - + /** + * Returns an immutable instance of [ProjectLogInsertParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ProjectLogInsertParams = ProjectLogInsertParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(events) { "`events` is required but was not set" }.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + projectId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Event.Deserializer::class) - @JsonSerialize(using = Event.Serializer::class) - class Event + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val insertProjectLogsEventReplace: InsertProjectLogsEventReplace? = null, - private val insertProjectLogsEventMerge: InsertProjectLogsEventMerge? = null, - private val _json: JsonValue? = null, + private val events: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("events") + @ExcludeMissing + events: JsonField> = JsonMissing.of() + ) : this(events, mutableMapOf()) + + /** + * A list of project logs events to insert + * + * @throws BraintrustInvalidDataException 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 events(): List = events.getRequired("events") + + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("events") + @ExcludeMissing + fun _events(): JsonField> = events - fun insertProjectLogsEventReplace(): InsertProjectLogsEventReplace? = - insertProjectLogsEventReplace + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - fun insertProjectLogsEventMerge(): InsertProjectLogsEventMerge? = - insertProjectLogsEventMerge + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun isInsertProjectLogsEventReplace(): Boolean = insertProjectLogsEventReplace != null + fun toBuilder() = Builder().from(this) - fun isInsertProjectLogsEventMerge(): Boolean = insertProjectLogsEventMerge != null + companion object { - fun asInsertProjectLogsEventReplace(): InsertProjectLogsEventReplace = - insertProjectLogsEventReplace.getOrThrow("insertProjectLogsEventReplace") + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + */ + fun builder() = Builder() + } - fun asInsertProjectLogsEventMerge(): InsertProjectLogsEventMerge = - insertProjectLogsEventMerge.getOrThrow("insertProjectLogsEventMerge") + /** A builder for [Body]. */ + class Builder internal constructor() { - fun _json(): JsonValue? = _json + private var events: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun accept(visitor: Visitor): T { - return when { - insertProjectLogsEventReplace != null -> - visitor.visitInsertProjectLogsEventReplace(insertProjectLogsEventReplace) - insertProjectLogsEventMerge != null -> - visitor.visitInsertProjectLogsEventMerge(insertProjectLogsEventMerge) - else -> visitor.unknown(_json) + internal fun from(body: Body) = apply { + events = body.events.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() } - } - fun validate(): Event = apply { - if (!validated) { - if (insertProjectLogsEventReplace == null && insertProjectLogsEventMerge == null) { - throw BraintrustInvalidDataException("Unknown Event: $_json") - } - insertProjectLogsEventReplace?.validate() - insertProjectLogsEventMerge?.validate() - validated = true + /** A list of project logs events to insert */ + fun events(events: List) = events(JsonField.of(events)) + + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed + * `List` value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun events(events: JsonField>) = apply { + this.events = events.map { it.toMutableList() } } - } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** + * Adds a single [InsertProjectLogsEvent] to [events]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEvent(event: InsertProjectLogsEvent) = apply { + events = + (events ?: JsonField.of(mutableListOf())).also { + checkKnown("events", it).add(event) + } } - return other is Event && - this.insertProjectLogsEventReplace == other.insertProjectLogsEventReplace && - this.insertProjectLogsEventMerge == other.insertProjectLogsEventMerge - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - override fun hashCode(): Int { - return Objects.hash(insertProjectLogsEventReplace, insertProjectLogsEventMerge) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - override fun toString(): String { - return when { - insertProjectLogsEventReplace != null -> - "Event{insertProjectLogsEventReplace=$insertProjectLogsEventReplace}" - insertProjectLogsEventMerge != null -> - "Event{insertProjectLogsEventMerge=$insertProjectLogsEventMerge}" - _json != null -> "Event{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Event") + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) } - } - companion object { + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun ofInsertProjectLogsEventReplace( - insertProjectLogsEventReplace: InsertProjectLogsEventReplace - ) = Event(insertProjectLogsEventReplace = insertProjectLogsEventReplace) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun ofInsertProjectLogsEventMerge( - insertProjectLogsEventMerge: InsertProjectLogsEventMerge - ) = Event(insertProjectLogsEventMerge = insertProjectLogsEventMerge) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("events", events).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - interface Visitor { + private var validated: Boolean = false - fun visitInsertProjectLogsEventReplace( - insertProjectLogsEventReplace: InsertProjectLogsEventReplace - ): T + fun validate(): Body = apply { + if (validated) { + return@apply + } - fun visitInsertProjectLogsEventMerge( - insertProjectLogsEventMerge: InsertProjectLogsEventMerge - ): T + events().forEach { it.validate() } + validated = true + } - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Event: $json") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - class Deserializer : BaseDeserializer(Event::class) { + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (events.asKnown()?.sumOf { it.validity().toInt() } ?: 0) - override fun ObjectCodec.deserialize(node: JsonNode): Event { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { - it.validate() - } - ?.let { - return Event(insertProjectLogsEventReplace = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { - it.validate() - } - ?.let { - return Event(insertProjectLogsEventMerge = it, _json = json) - } - - return Event(_json = json) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Body && + events == other.events && + additionalProperties == other.additionalProperties } - class Serializer : BaseSerializer(Event::class) { - - override fun serialize( - value: Event, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.insertProjectLogsEventReplace != null -> - generator.writeObject(value.insertProjectLogsEventReplace) - value.insertProjectLogsEventMerge != null -> - generator.writeObject(value.insertProjectLogsEventMerge) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Event") - } - } + private val hashCode: Int by lazy { Objects.hash(events, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Body{events=$events, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is ProjectLogInsertParams && + projectId == other.projectId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(projectId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectLogInsertParams{projectId=$projectId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogsEvent.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogsEvent.kt index 618dd3b3..14971fc7 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogsEvent.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectLogsEvent.kt @@ -7,50 +7,109 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ProjectLogsEvent.Builder::class) -@NoAutoDetect class ProjectLogsEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val _xactId: JsonField, private val created: JsonField, + private val logId: JsonField, private val orgId: JsonField, private val projectId: JsonField, - private val logId: JsonField, - private val input: JsonValue, - private val output: JsonValue, - private val expected: JsonValue, + private val rootSpanId: JsonField, + private val spanId: JsonField, + private val context: JsonField, private val error: JsonValue, - private val scores: JsonField, + private val expected: JsonValue, + private val input: JsonValue, + private val isRoot: JsonField, private val metadata: JsonField, - private val tags: JsonField>, private val metrics: JsonField, - private val context: JsonField, - private val spanId: JsonField, - private val spanParents: JsonField>, - private val rootSpanId: JsonField, + private val origin: JsonField, + private val output: JsonValue, + private val scores: JsonField, private val spanAttributes: JsonField, - private val additionalProperties: Map, + private val spanParents: JsonField>, + private val tags: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_xact_id") @ExcludeMissing _xactId: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("log_id") @ExcludeMissing logId: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("root_span_id") + @ExcludeMissing + rootSpanId: JsonField = JsonMissing.of(), + @JsonProperty("span_id") @ExcludeMissing spanId: JsonField = JsonMissing.of(), + @JsonProperty("context") @ExcludeMissing context: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonValue = JsonMissing.of(), + @JsonProperty("expected") @ExcludeMissing expected: JsonValue = JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonValue = JsonMissing.of(), + @JsonProperty("is_root") @ExcludeMissing isRoot: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("metrics") @ExcludeMissing metrics: JsonField = JsonMissing.of(), + @JsonProperty("origin") + @ExcludeMissing + origin: JsonField = JsonMissing.of(), + @JsonProperty("output") @ExcludeMissing output: JsonValue = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + @JsonProperty("span_attributes") + @ExcludeMissing + spanAttributes: JsonField = JsonMissing.of(), + @JsonProperty("span_parents") + @ExcludeMissing + spanParents: JsonField> = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _xactId, + created, + logId, + orgId, + projectId, + rootSpanId, + spanId, + context, + error, + expected, + input, + isRoot, + metadata, + metrics, + origin, + output, + scores, + spanAttributes, + spanParents, + tags, + mutableMapOf(), + ) /** * A unique identifier for the project logs event. If you don't provide one, BrainTrust will * generate one for you + * + * @throws BraintrustInvalidDataException 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") @@ -58,32 +117,74 @@ private constructor( * The transaction id of an event is unique to the network operation that processed the event * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve * a versioned snapshot of the project logs (see the `version` parameter) + * + * @throws BraintrustInvalidDataException 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 _xactId(): String = _xactId.getRequired("_xact_id") - /** The timestamp the project logs event was created */ + /** + * The timestamp the project logs event was created + * + * @throws BraintrustInvalidDataException 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 created(): OffsetDateTime = created.getRequired("created") - /** Unique id for the organization that the project belongs under */ + /** + * A literal 'g' which identifies the log as a project log + * + * @throws BraintrustInvalidDataException 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 logId(): LogId = logId.getRequired("log_id") + + /** + * Unique id for the organization that the project belongs under + * + * @throws BraintrustInvalidDataException 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 orgId(): String = orgId.getRequired("org_id") - /** Unique identifier for the project */ + /** + * Unique identifier for the project + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** A literal 'g' which identifies the log as a project log */ - fun logId(): LogId = logId.getRequired("log_id") + /** + * A unique identifier for the trace this project logs event belongs to + * + * @throws BraintrustInvalidDataException 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 rootSpanId(): String = rootSpanId.getRequired("root_span_id") - /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ - fun input(): JsonValue = input + /** + * A unique identifier used to link different project logs events together as part of a full + * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full + * details on tracing + * + * @throws BraintrustInvalidDataException 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 spanId(): String = spanId.getRequired("span_id") /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question. + * Context is additional information about the code that produced the project logs event. It is + * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the + * location in code which produced the project logs event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun output(): JsonValue = output + fun context(): Context? = context.getNullable("context") + + /** The error that occurred, if any. */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonValue = error /** * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to @@ -93,21 +194,18 @@ private constructor( * analyses. However, we may later use these values to re-score outputs or fine-tune your * models. */ - fun expected(): JsonValue = expected + @JsonProperty("expected") @ExcludeMissing fun _expected(): JsonValue = expected - /** The error that occurred, if any. */ - fun error(): JsonValue = error + /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonValue = input /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. + * Whether this span is a root span + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun scores(): Scores? = scores.getNullable("scores") + fun isRoot(): Boolean? = isRoot.getNullable("is_root") /** * A dictionary with additional data about the test example, model outputs, or just about @@ -115,291 +213,282 @@ private constructor( * example, you could log the `prompt`, example's `id`, or anything else that would be useful to * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys * must be strings + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metadata(): Metadata? = metadata.getNullable("metadata") - /** A list of tags to log */ - fun tags(): List? = tags.getNullable("tags") - /** * Metrics are numerical measurements tracking the execution of the code that produced the * project logs event. Use "start" and "end" to track the time span over which the project logs * event was produced + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun metrics(): Metrics? = metrics.getNullable("metrics") /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event + * Indicates the event was copied from another object. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun context(): Context? = context.getNullable("context") + fun origin(): ObjectReference? = origin.getNullable("origin") /** - * A unique identifier used to link different project logs events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * The output of your application, including post-processing (an arbitrary, JSON serializable + * object), that allows you to determine whether the result is correct or not. For example, in + * an app that generates SQL queries, the `output` should be the _result_ of the SQL query + * generated by the model, not the query itself, because there may be multiple valid queries + * that answer a single question. */ - fun spanId(): String = spanId.getRequired("span_id") + @JsonProperty("output") @ExcludeMissing fun _output(): JsonValue = output + + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare logs. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun scores(): Scores? = scores.getNullable("scores") + + /** + * Human-identifying attributes of the span, such as name, type, etc. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") /** * An array of the parent `span_ids` of this project logs event. This should be empty for the * root span of a trace, and should most often contain just one parent element for subspans + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun spanParents(): List? = spanParents.getNullable("span_parents") - /** The `span_id` of the root of the trace this project logs event belongs to */ - fun rootSpanId(): String = rootSpanId.getRequired("root_span_id") - - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(): SpanAttributes? = spanAttributes.getNullable("span_attributes") - /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you + * A list of tags to log + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("id") @ExcludeMissing fun _id() = id + fun tags(): List? = tags.getNullable("tags") /** - * The transaction id of an event is unique to the network operation that processed the event - * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve - * a versioned snapshot of the project logs (see the `version` parameter) + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("_xact_id") @ExcludeMissing fun __xactId() = _xactId + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id - /** The timestamp the project logs event was created */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * Returns the raw JSON value of [_xactId]. + * + * Unlike [_xactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_xact_id") @ExcludeMissing fun __xactId(): JsonField = _xactId - /** Unique id for the organization that the project belongs under */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - /** Unique identifier for the project */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId + /** + * Returns the raw JSON value of [logId]. + * + * Unlike [logId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("log_id") @ExcludeMissing fun _logId(): JsonField = logId - /** A literal 'g' which identifies the log as a project log */ - @JsonProperty("log_id") @ExcludeMissing fun _logId() = logId + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId - /** The arguments that uniquely define a user input (an arbitrary, JSON serializable object). */ - @JsonProperty("input") @ExcludeMissing fun _input() = input + /** + * 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 /** - * The output of your application, including post-processing (an arbitrary, JSON serializable - * object), that allows you to determine whether the result is correct or not. For example, in - * an app that generates SQL queries, the `output` should be the _result_ of the SQL query - * generated by the model, not the query itself, because there may be multiple valid queries - * that answer a single question. + * Returns the raw JSON value of [rootSpanId]. + * + * Unlike [rootSpanId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("output") @ExcludeMissing fun _output() = output + @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId(): JsonField = rootSpanId /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does not - * compare `output` to `expected` for you, since there are so many different ways to do that - * correctly. Instead, these values are just used to help you navigate while digging into - * analyses. However, we may later use these values to re-score outputs or fine-tune your - * models. + * Returns the raw JSON value of [spanId]. + * + * Unlike [spanId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("expected") @ExcludeMissing fun _expected() = expected + @JsonProperty("span_id") @ExcludeMissing fun _spanId(): JsonField = spanId - /** The error that occurred, if any. */ - @JsonProperty("error") @ExcludeMissing fun _error() = error + /** + * 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 /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. + * Returns the raw JSON value of [isRoot]. + * + * Unlike [isRoot], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores + @JsonProperty("is_root") @ExcludeMissing fun _isRoot(): JsonField = isRoot /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. For - * example, you could log the `prompt`, example's `id`, or anything else that would be useful to - * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys - * must be strings + * 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() = metadata + @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata - /** A list of tags to log */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags + /** + * Returns the raw JSON value of [metrics]. + * + * Unlike [metrics], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metrics") @ExcludeMissing fun _metrics(): JsonField = metrics /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project logs - * event was produced + * Returns the raw JSON value of [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("metrics") @ExcludeMissing fun _metrics() = metrics + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin /** - * Context is additional information about the code that produced the project logs event. It is - * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the - * location in code which produced the project logs event + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("context") @ExcludeMissing fun _context() = context + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores /** - * A unique identifier used to link different project logs events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * Returns the raw JSON value of [spanAttributes]. + * + * Unlike [spanAttributes], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("span_id") @ExcludeMissing fun _spanId() = spanId + @JsonProperty("span_attributes") + @ExcludeMissing + fun _spanAttributes(): JsonField = spanAttributes /** - * An array of the parent `span_ids` of this project logs event. This should be empty for the - * root span of a trace, and should most often contain just one parent element for subspans + * Returns the raw JSON value of [spanParents]. + * + * Unlike [spanParents], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("span_parents") @ExcludeMissing fun _spanParents() = spanParents + @JsonProperty("span_parents") + @ExcludeMissing + fun _spanParents(): JsonField> = spanParents - /** The `span_id` of the root of the trace this project logs event belongs to */ - @JsonProperty("root_span_id") @ExcludeMissing fun _rootSpanId() = rootSpanId + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") @ExcludeMissing fun _spanAttributes() = spanAttributes + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ProjectLogsEvent = apply { - if (!validated) { - id() - _xactId() - created() - orgId() - projectId() - logId() - input() - output() - expected() - error() - scores()?.validate() - metadata()?.validate() - tags() - metrics()?.validate() - context()?.validate() - spanId() - spanParents() - rootSpanId() - spanAttributes()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectLogsEvent && - this.id == other.id && - this._xactId == other._xactId && - this.created == other.created && - this.orgId == other.orgId && - this.projectId == other.projectId && - this.logId == other.logId && - this.input == other.input && - this.output == other.output && - this.expected == other.expected && - this.error == other.error && - this.scores == other.scores && - this.metadata == other.metadata && - this.tags == other.tags && - this.metrics == other.metrics && - this.context == other.context && - this.spanId == other.spanId && - this.spanParents == other.spanParents && - this.rootSpanId == other.rootSpanId && - this.spanAttributes == other.spanAttributes && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - _xactId, - created, - orgId, - projectId, - logId, - input, - output, - expected, - error, - scores, - metadata, - tags, - metrics, - context, - spanId, - spanParents, - rootSpanId, - spanAttributes, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ProjectLogsEvent{id=$id, _xactId=$_xactId, created=$created, orgId=$orgId, projectId=$projectId, logId=$logId, input=$input, output=$output, expected=$expected, error=$error, scores=$scores, metadata=$metadata, tags=$tags, metrics=$metrics, context=$context, spanId=$spanId, spanParents=$spanParents, rootSpanId=$rootSpanId, spanAttributes=$spanAttributes, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ProjectLogsEvent]. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .created() + * .logId() + * .orgId() + * .projectId() + * .rootSpanId() + * .spanId() + * ``` + */ fun builder() = Builder() } - class Builder { - - private var id: JsonField = JsonMissing.of() - private var _xactId: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var orgId: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var logId: JsonField = JsonMissing.of() - private var input: JsonValue = JsonMissing.of() - private var output: JsonValue = JsonMissing.of() - private var expected: JsonValue = JsonMissing.of() + /** A builder for [ProjectLogsEvent]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var _xactId: JsonField? = null + private var created: JsonField? = null + private var logId: JsonField? = null + private var orgId: JsonField? = null + private var projectId: JsonField? = null + private var rootSpanId: JsonField? = null + private var spanId: JsonField? = null + private var context: JsonField = JsonMissing.of() private var error: JsonValue = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() + private var expected: JsonValue = JsonMissing.of() + private var input: JsonValue = JsonMissing.of() + private var isRoot: JsonField = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() private var metrics: JsonField = JsonMissing.of() - private var context: JsonField = JsonMissing.of() - private var spanId: JsonField = JsonMissing.of() - private var spanParents: JsonField> = JsonMissing.of() - private var rootSpanId: JsonField = JsonMissing.of() + private var origin: JsonField = JsonMissing.of() + private var output: JsonValue = JsonMissing.of() + private var scores: JsonField = JsonMissing.of() private var spanAttributes: JsonField = JsonMissing.of() + private var spanParents: JsonField>? = null + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectLogsEvent: ProjectLogsEvent) = apply { - this.id = projectLogsEvent.id - this._xactId = projectLogsEvent._xactId - this.created = projectLogsEvent.created - this.orgId = projectLogsEvent.orgId - this.projectId = projectLogsEvent.projectId - this.logId = projectLogsEvent.logId - this.input = projectLogsEvent.input - this.output = projectLogsEvent.output - this.expected = projectLogsEvent.expected - this.error = projectLogsEvent.error - this.scores = projectLogsEvent.scores - this.metadata = projectLogsEvent.metadata - this.tags = projectLogsEvent.tags - this.metrics = projectLogsEvent.metrics - this.context = projectLogsEvent.context - this.spanId = projectLogsEvent.spanId - this.spanParents = projectLogsEvent.spanParents - this.rootSpanId = projectLogsEvent.rootSpanId - this.spanAttributes = projectLogsEvent.spanAttributes - additionalProperties(projectLogsEvent.additionalProperties) + id = projectLogsEvent.id + _xactId = projectLogsEvent._xactId + created = projectLogsEvent.created + logId = projectLogsEvent.logId + orgId = projectLogsEvent.orgId + projectId = projectLogsEvent.projectId + rootSpanId = projectLogsEvent.rootSpanId + spanId = projectLogsEvent.spanId + context = projectLogsEvent.context + error = projectLogsEvent.error + expected = projectLogsEvent.expected + input = projectLogsEvent.input + isRoot = projectLogsEvent.isRoot + metadata = projectLogsEvent.metadata + metrics = projectLogsEvent.metrics + origin = projectLogsEvent.origin + output = projectLogsEvent.output + scores = projectLogsEvent.scores + spanAttributes = projectLogsEvent.spanAttributes + spanParents = projectLogsEvent.spanParents.map { it.toMutableList() } + tags = projectLogsEvent.tags.map { it.toMutableList() } + additionalProperties = projectLogsEvent.additionalProperties.toMutableMap() } /** @@ -409,10 +498,12 @@ private constructor( fun id(id: String) = id(JsonField.of(id)) /** - * A unique identifier for the project logs event. If you don't provide one, BrainTrust will - * generate one for you + * 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. */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } + fun id(id: JsonField) = apply { this.id = id } /** * The transaction id of an event is unique to the network operation that processed the @@ -422,104 +513,136 @@ private constructor( fun _xactId(_xactId: String) = _xactId(JsonField.of(_xactId)) /** - * The transaction id of an event is unique to the network operation that processed the - * event insertion. Transaction ids are monotonically increasing over time and can be used - * to retrieve a versioned snapshot of the project logs (see the `version` parameter) + * Sets [Builder._xactId] to an arbitrary JSON value. + * + * You should usually call [Builder._xactId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("_xact_id") - @ExcludeMissing fun _xactId(_xactId: JsonField) = apply { this._xactId = _xactId } /** The timestamp the project logs event was created */ fun created(created: OffsetDateTime) = created(JsonField.of(created)) - /** The timestamp the project logs event was created */ - @JsonProperty("created") - @ExcludeMissing + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } + /** A literal 'g' which identifies the log as a project log */ + fun logId(logId: LogId) = logId(JsonField.of(logId)) + + /** + * Sets [Builder.logId] to an arbitrary JSON value. + * + * You should usually call [Builder.logId] with a well-typed [LogId] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun logId(logId: JsonField) = apply { this.logId = logId } + /** Unique id for the organization that the project belongs under */ fun orgId(orgId: String) = orgId(JsonField.of(orgId)) - /** Unique id for the organization that the project belongs under */ - @JsonProperty("org_id") - @ExcludeMissing + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun orgId(orgId: JsonField) = apply { this.orgId = orgId } /** Unique identifier for the project */ fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Unique identifier for the project */ - @JsonProperty("project_id") - @ExcludeMissing + /** + * 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 } - /** A literal 'g' which identifies the log as a project log */ - fun logId(logId: LogId) = logId(JsonField.of(logId)) + /** A unique identifier for the trace this project logs event belongs to */ + fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) - /** A literal 'g' which identifies the log as a project log */ - @JsonProperty("log_id") - @ExcludeMissing - fun logId(logId: JsonField) = apply { this.logId = logId } + /** + * Sets [Builder.rootSpanId] to an arbitrary JSON value. + * + * You should usually call [Builder.rootSpanId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } /** - * The arguments that uniquely define a user input (an arbitrary, JSON serializable object). + * A unique identifier used to link different project logs events together as part of a full + * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full + * details on tracing */ - @JsonProperty("input") - @ExcludeMissing - fun input(input: JsonValue) = apply { this.input = input } + fun spanId(spanId: String) = spanId(JsonField.of(spanId)) /** - * The output of your application, including post-processing (an arbitrary, JSON - * serializable object), that allows you to determine whether the result is correct or not. - * For example, in an app that generates SQL queries, the `output` should be the _result_ of - * the SQL query generated by the model, not the query itself, because there may be multiple - * valid queries that answer a single question. + * Sets [Builder.spanId] to an arbitrary JSON value. + * + * You should usually call [Builder.spanId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("output") - @ExcludeMissing - fun output(output: JsonValue) = apply { this.output = output } + fun spanId(spanId: JsonField) = apply { this.spanId = spanId } /** - * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to - * `output` to determine if your `output` value is correct or not. Braintrust currently does + * Context is additional information about the code that produced the project logs event. It + * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to + * track the location in code which produced the project logs event + */ + fun context(context: Context?) = context(JsonField.ofNullable(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 } + + /** The error that occurred, if any. */ + fun error(error: JsonValue) = apply { this.error = error } + + /** + * The ground truth value (an arbitrary, JSON serializable object) that you'd compare to + * `output` to determine if your `output` value is correct or not. Braintrust currently does * not compare `output` to `expected` for you, since there are so many different ways to do * that correctly. Instead, these values are just used to help you navigate while digging * into analyses. However, we may later use these values to re-score outputs or fine-tune * your models. */ - @JsonProperty("expected") - @ExcludeMissing fun expected(expected: JsonValue) = apply { this.expected = expected } - /** The error that occurred, if any. */ - @JsonProperty("error") - @ExcludeMissing - fun error(error: JsonValue) = apply { this.error = error } + /** + * The arguments that uniquely define a user input (an arbitrary, JSON serializable object). + */ + fun input(input: JsonValue) = apply { this.input = input } + + /** Whether this span is a root span */ + fun isRoot(isRoot: Boolean?) = isRoot(JsonField.ofNullable(isRoot)) /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare logs. + * Alias for [Builder.isRoot]. + * + * This unboxed primitive overload exists for backwards compatibility. */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) + fun isRoot(isRoot: Boolean) = isRoot(isRoot as Boolean?) /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a - * variety of signals that help you determine how accurate the outputs are compared to what - * you expect and diagnose failures. For example, a summarization app might have one score - * that tells you how accurate the summary is, and another that measures the word similarity - * between the generated and grouth truth summary. The word similarity score could help you - * determine whether the summarization was covering similar concepts or not. You can use - * these scores to help you sort, filter, and compare logs. + * Sets [Builder.isRoot] to an arbitrary JSON value. + * + * You should usually call [Builder.isRoot] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("scores") - @ExcludeMissing - fun scores(scores: JsonField) = apply { this.scores = scores } + fun isRoot(isRoot: JsonField) = apply { this.isRoot = isRoot } /** * A dictionary with additional data about the test example, model outputs, or just about @@ -528,200 +651,382 @@ private constructor( * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, * but its keys must be strings */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) /** - * A dictionary with additional data about the test example, model outputs, or just about - * anything else that's relevant, that you can use to help find and analyze examples later. - * For example, you could log the `prompt`, example's `id`, or anything else that would be - * useful to slice/dice later. The values in `metadata` can be any JSON-serializable type, - * but its keys must be strings + * 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. */ - @JsonProperty("metadata") - @ExcludeMissing fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - /** A list of tags to log */ - fun tags(tags: List) = tags(JsonField.of(tags)) - - /** A list of tags to log */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } - /** * Metrics are numerical measurements tracking the execution of the code that produced the * project logs event. Use "start" and "end" to track the time span over which the project * logs event was produced */ - fun metrics(metrics: Metrics) = metrics(JsonField.of(metrics)) + fun metrics(metrics: Metrics?) = metrics(JsonField.ofNullable(metrics)) /** - * Metrics are numerical measurements tracking the execution of the code that produced the - * project logs event. Use "start" and "end" to track the time span over which the project - * logs event was produced + * Sets [Builder.metrics] to an arbitrary JSON value. + * + * You should usually call [Builder.metrics] with a well-typed [Metrics] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("metrics") - @ExcludeMissing fun metrics(metrics: JsonField) = apply { this.metrics = metrics } + /** Indicates the event was copied from another object. */ + fun origin(origin: ObjectReference?) = origin(JsonField.ofNullable(origin)) + /** - * Context is additional information about the code that produced the project logs event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the project logs event + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [ObjectReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun context(context: Context) = context(JsonField.of(context)) + fun origin(origin: JsonField) = apply { this.origin = origin } /** - * Context is additional information about the code that produced the project logs event. It - * is essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to - * track the location in code which produced the project logs event + * The output of your application, including post-processing (an arbitrary, JSON + * serializable object), that allows you to determine whether the result is correct or not. + * For example, in an app that generates SQL queries, the `output` should be the _result_ of + * the SQL query generated by the model, not the query itself, because there may be multiple + * valid queries that answer a single question. */ - @JsonProperty("context") - @ExcludeMissing - fun context(context: JsonField) = apply { this.context = context } + fun output(output: JsonValue) = apply { this.output = output } /** - * A unique identifier used to link different project logs events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a + * variety of signals that help you determine how accurate the outputs are compared to what + * you expect and diagnose failures. For example, a summarization app might have one score + * that tells you how accurate the summary is, and another that measures the word similarity + * between the generated and grouth truth summary. The word similarity score could help you + * determine whether the summarization was covering similar concepts or not. You can use + * these scores to help you sort, filter, and compare logs. */ - fun spanId(spanId: String) = spanId(JsonField.of(spanId)) + fun scores(scores: Scores?) = scores(JsonField.ofNullable(scores)) /** - * A unique identifier used to link different project logs events together as part of a full - * trace. See the [tracing guide](https://www.braintrust.dev/docs/guides/tracing) for full - * details on tracing + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("span_id") - @ExcludeMissing - fun spanId(spanId: JsonField) = apply { this.spanId = spanId } + fun scores(scores: JsonField) = apply { this.scores = scores } + + /** Human-identifying attributes of the span, such as name, type, etc. */ + fun spanAttributes(spanAttributes: SpanAttributes?) = + spanAttributes(JsonField.ofNullable(spanAttributes)) /** - * An array of the parent `span_ids` of this project logs event. This should be empty for - * the root span of a trace, and should most often contain just one parent element for - * subspans + * Sets [Builder.spanAttributes] to an arbitrary JSON value. + * + * You should usually call [Builder.spanAttributes] with a well-typed [SpanAttributes] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun spanParents(spanParents: List) = spanParents(JsonField.of(spanParents)) + fun spanAttributes(spanAttributes: JsonField) = apply { + this.spanAttributes = spanAttributes + } /** * An array of the parent `span_ids` of this project logs event. This should be empty for * the root span of a trace, and should most often contain just one parent element for * subspans */ - @JsonProperty("span_parents") - @ExcludeMissing + fun spanParents(spanParents: List?) = spanParents(JsonField.ofNullable(spanParents)) + + /** + * Sets [Builder.spanParents] to an arbitrary JSON value. + * + * You should usually call [Builder.spanParents] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun spanParents(spanParents: JsonField>) = apply { - this.spanParents = spanParents + this.spanParents = spanParents.map { it.toMutableList() } } - /** The `span_id` of the root of the trace this project logs event belongs to */ - fun rootSpanId(rootSpanId: String) = rootSpanId(JsonField.of(rootSpanId)) + /** + * Adds a single [String] to [spanParents]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSpanParent(spanParent: String) = apply { + spanParents = + (spanParents ?: JsonField.of(mutableListOf())).also { + checkKnown("spanParents", it).add(spanParent) + } + } - /** The `span_id` of the root of the trace this project logs event belongs to */ - @JsonProperty("root_span_id") - @ExcludeMissing - fun rootSpanId(rootSpanId: JsonField) = apply { this.rootSpanId = rootSpanId } + /** A list of tags to log */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) - /** Human-identifying attributes of the span, such as name, type, etc. */ - fun spanAttributes(spanAttributes: SpanAttributes) = - spanAttributes(JsonField.of(spanAttributes)) + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonProperty("span_attributes") - @ExcludeMissing - fun spanAttributes(spanAttributes: JsonField) = apply { - this.spanAttributes = spanAttributes + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ProjectLogsEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .created() + * .logId() + * .orgId() + * .projectId() + * .rootSpanId() + * .spanId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ProjectLogsEvent = ProjectLogsEvent( - id, - _xactId, - created, - orgId, - projectId, - logId, - input, - output, - expected, + checkRequired("id", id), + checkRequired("_xactId", _xactId), + checkRequired("created", created), + checkRequired("logId", logId), + checkRequired("orgId", orgId), + checkRequired("projectId", projectId), + checkRequired("rootSpanId", rootSpanId), + checkRequired("spanId", spanId), + context, error, - scores, + expected, + input, + isRoot, metadata, - tags.map { it.toUnmodifiable() }, metrics, - context, - spanId, - spanParents.map { it.toUnmodifiable() }, - rootSpanId, + origin, + output, + scores, spanAttributes, - additionalProperties.toUnmodifiable(), + (spanParents ?: JsonMissing.of()).map { it.toImmutable() }, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } - class LogId - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): ProjectLogsEvent = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + id() + _xactId() + created() + logId().validate() + orgId() + projectId() + rootSpanId() + spanId() + context()?.validate() + isRoot() + metadata()?.validate() + metrics()?.validate() + origin()?.validate() + scores()?.validate() + spanAttributes()?.validate() + spanParents() + tags() + validated = true + } - return other is LogId && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_xactId.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (logId.asKnown()?.validity() ?: 0) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (rootSpanId.asKnown() == null) 0 else 1) + + (if (spanId.asKnown() == null) 0 else 1) + + (context.asKnown()?.validity() ?: 0) + + (if (isRoot.asKnown() == null) 0 else 1) + + (metadata.asKnown()?.validity() ?: 0) + + (metrics.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (scores.asKnown()?.validity() ?: 0) + + (spanAttributes.asKnown()?.validity() ?: 0) + + (spanParents.asKnown()?.size ?: 0) + + (tags.asKnown()?.size ?: 0) - override fun toString() = value.toString() + /** A literal 'g' which identifies the log as a project log */ + class LogId @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 { - val G = LogId(JsonField.of("g")) + val G = of("g") fun of(value: String) = LogId(JsonField.of(value)) } + /** An enum containing [LogId]'s known values. */ enum class Known { - G, + G } + /** + * An enum containing [LogId]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [LogId] 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 { G, + /** An enum member indicating that [LogId] 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) { G -> Value.G 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { G -> Known.G else -> throw BraintrustInvalidDataException("Unknown LogId: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): LogId = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 LogId && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } /** @@ -729,156 +1034,251 @@ private constructor( * essentially the textual counterpart to `metrics`. Use the `caller_*` attributes to track the * location in code which produced the project logs event */ - @JsonDeserialize(builder = Context.Builder::class) - @NoAutoDetect class Context + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val callerFunctionname: JsonField, private val callerFilename: JsonField, + private val callerFunctionname: JsonField, private val callerLineno: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonField = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonField = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonField = JsonMissing.of(), + ) : this(callerFilename, callerFunctionname, callerLineno, mutableMapOf()) - private var hashCode: Int = 0 + /** + * Name of the file in code where the project logs event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - /** The function in code which created the project logs event */ + /** + * The function in code which created the project logs event + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ fun callerFunctionname(): String? = callerFunctionname.getNullable("caller_functionname") - /** Name of the file in code where the project logs event was created */ - fun callerFilename(): String? = callerFilename.getNullable("caller_filename") - - /** Line of code where the project logs event was created */ + /** + * Line of code where the project logs event was created + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ fun callerLineno(): Long? = callerLineno.getNullable("caller_lineno") - /** The function in code which created the project logs event */ + /** + * Returns the raw JSON value of [callerFilename]. + * + * Unlike [callerFilename], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonField = callerFilename + + /** + * Returns the raw JSON value of [callerFunctionname]. + * + * Unlike [callerFunctionname], this method doesn't throw if the JSON field has an + * unexpected type. + */ @JsonProperty("caller_functionname") @ExcludeMissing - fun _callerFunctionname() = callerFunctionname + fun _callerFunctionname(): JsonField = callerFunctionname - /** Name of the file in code where the project logs event was created */ - @JsonProperty("caller_filename") @ExcludeMissing fun _callerFilename() = callerFilename + /** + * Returns the raw JSON value of [callerLineno]. + * + * Unlike [callerLineno], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("caller_lineno") + @ExcludeMissing + fun _callerLineno(): JsonField = callerLineno - /** Line of code where the project logs event was created */ - @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno() = callerLineno + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Context = apply { - if (!validated) { - callerFunctionname() - callerFilename() - callerLineno() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Context && - this.callerFunctionname == other.callerFunctionname && - this.callerFilename == other.callerFilename && - this.callerLineno == other.callerLineno && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - callerFunctionname, - callerFilename, - callerLineno, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Context{callerFunctionname=$callerFunctionname, callerFilename=$callerFilename, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Context]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Context]. */ + class Builder internal constructor() { - private var callerFunctionname: JsonField = JsonMissing.of() private var callerFilename: JsonField = JsonMissing.of() + private var callerFunctionname: JsonField = JsonMissing.of() private var callerLineno: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(context: Context) = apply { - this.callerFunctionname = context.callerFunctionname - this.callerFilename = context.callerFilename - this.callerLineno = context.callerLineno - additionalProperties(context.additionalProperties) - } - - /** The function in code which created the project logs event */ - fun callerFunctionname(callerFunctionname: String) = - callerFunctionname(JsonField.of(callerFunctionname)) - - /** The function in code which created the project logs event */ - @JsonProperty("caller_functionname") - @ExcludeMissing - fun callerFunctionname(callerFunctionname: JsonField) = apply { - this.callerFunctionname = callerFunctionname + callerFilename = context.callerFilename + callerFunctionname = context.callerFunctionname + callerLineno = context.callerLineno + additionalProperties = context.additionalProperties.toMutableMap() } /** Name of the file in code where the project logs event was created */ - fun callerFilename(callerFilename: String) = - callerFilename(JsonField.of(callerFilename)) + fun callerFilename(callerFilename: String?) = + callerFilename(JsonField.ofNullable(callerFilename)) - /** Name of the file in code where the project logs event was created */ - @JsonProperty("caller_filename") - @ExcludeMissing + /** + * Sets [Builder.callerFilename] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFilename] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun callerFilename(callerFilename: JsonField) = apply { this.callerFilename = callerFilename } - /** Line of code where the project logs event was created */ - fun callerLineno(callerLineno: Long) = callerLineno(JsonField.of(callerLineno)) + /** The function in code which created the project logs event */ + fun callerFunctionname(callerFunctionname: String?) = + callerFunctionname(JsonField.ofNullable(callerFunctionname)) + + /** + * Sets [Builder.callerFunctionname] to an arbitrary JSON value. + * + * You should usually call [Builder.callerFunctionname] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun callerFunctionname(callerFunctionname: JsonField) = apply { + this.callerFunctionname = callerFunctionname + } /** Line of code where the project logs event was created */ - @JsonProperty("caller_lineno") - @ExcludeMissing + fun callerLineno(callerLineno: Long?) = callerLineno(JsonField.ofNullable(callerLineno)) + + /** + * Alias for [Builder.callerLineno]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun callerLineno(callerLineno: Long) = callerLineno(callerLineno as Long?) + + /** + * Sets [Builder.callerLineno] to an arbitrary JSON value. + * + * You should usually call [Builder.callerLineno] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun callerLineno(callerLineno: JsonField) = apply { this.callerLineno = callerLineno } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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. + */ fun build(): Context = Context( - callerFunctionname, callerFilename, + callerFunctionname, callerLineno, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): Context = apply { + if (validated) { + return@apply + } + + callerFilename() + callerFunctionname() + callerLineno() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (callerFilename.asKnown() == null) 0 else 1) + + (if (callerFunctionname.asKnown() == null) 0 else 1) + + (if (callerLineno.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Context && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(callerFilename, callerFunctionname, callerLineno, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Context{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, additionalProperties=$additionalProperties}" } /** @@ -888,75 +1288,144 @@ private constructor( * slice/dice later. The values in `metadata` can be any JSON-serializable type, but its keys * must be strings */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect class Metadata + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val additionalProperties: Map, + private val model: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metadata = apply { - if (!validated) { - validated = true - } - } + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of() + ) : this(model, mutableMapOf()) - fun toBuilder() = Builder().from(this) + /** + * The model used for this example + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): String? = model.getNullable("model") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * 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 - return other is Metadata && this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [Metadata]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { + private var model: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + model = metadata.model + additionalProperties = metadata.additionalProperties.toMutableMap() } + /** The model used for this example */ + fun model(model: String?) = model(JsonField.ofNullable(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 additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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(model, additionalProperties.toMutableMap()) } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + model() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (model.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && + model == other.model && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(model, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metadata{model=$model, additionalProperties=$additionalProperties}" } /** @@ -964,525 +1433,595 @@ private constructor( * project logs event. Use "start" and "end" to track the time span over which the project logs * event was produced */ - @JsonDeserialize(builder = Metrics.Builder::class) - @NoAutoDetect class Metrics + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val start: JsonField, + private val callerFilename: JsonValue, + private val callerFunctionname: JsonValue, + private val callerLineno: JsonValue, + private val completionTokens: JsonField, private val end: JsonField, private val promptTokens: JsonField, - private val completionTokens: JsonField, + private val start: JsonField, private val tokens: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("caller_filename") + @ExcludeMissing + callerFilename: JsonValue = JsonMissing.of(), + @JsonProperty("caller_functionname") + @ExcludeMissing + callerFunctionname: JsonValue = JsonMissing.of(), + @JsonProperty("caller_lineno") + @ExcludeMissing + callerLineno: JsonValue = JsonMissing.of(), + @JsonProperty("completion_tokens") + @ExcludeMissing + completionTokens: JsonField = JsonMissing.of(), + @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), + @JsonProperty("prompt_tokens") + @ExcludeMissing + promptTokens: JsonField = JsonMissing.of(), + @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), + @JsonProperty("tokens") @ExcludeMissing tokens: JsonField = JsonMissing.of(), + ) : this( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + mutableMapOf(), + ) + + /** This metric is deprecated */ + @JsonProperty("caller_filename") + @ExcludeMissing + fun _callerFilename(): JsonValue = callerFilename + + /** This metric is deprecated */ + @JsonProperty("caller_functionname") + @ExcludeMissing + fun _callerFunctionname(): JsonValue = callerFunctionname - private var hashCode: Int = 0 + /** This metric is deprecated */ + @JsonProperty("caller_lineno") @ExcludeMissing fun _callerLineno(): JsonValue = callerLineno /** - * A unix timestamp recording when the section of code which produced the project logs event - * started + * The number of tokens in the completion generated by the model (only set if this is an LLM + * span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun start(): Double? = start.getNullable("start") + fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") /** * A unix timestamp recording when the section of code which produced the project logs event * finished + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ fun end(): Double? = end.getNullable("end") /** * The number of tokens in the prompt used to generate the project logs event (only set if * this is an LLM span) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ fun promptTokens(): Long? = promptTokens.getNullable("prompt_tokens") /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) + * A unix timestamp recording when the section of code which produced the project logs event + * started + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun completionTokens(): Long? = completionTokens.getNullable("completion_tokens") + fun start(): Double? = start.getNullable("start") - /** The total number of tokens in the input and output of the project logs event. */ + /** + * The total number of tokens in the input and output of the project logs event. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ fun tokens(): Long? = tokens.getNullable("tokens") /** - * A unix timestamp recording when the section of code which produced the project logs event - * started + * Returns the raw JSON value of [completionTokens]. + * + * Unlike [completionTokens], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("start") @ExcludeMissing fun _start() = start + @JsonProperty("completion_tokens") + @ExcludeMissing + fun _completionTokens(): JsonField = completionTokens /** - * A unix timestamp recording when the section of code which produced the project logs event - * finished + * Returns the raw JSON value of [end]. + * + * Unlike [end], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("end") @ExcludeMissing fun _end() = end + @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end /** - * The number of tokens in the prompt used to generate the project logs event (only set if - * this is an LLM span) + * Returns the raw JSON value of [promptTokens]. + * + * Unlike [promptTokens], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("prompt_tokens") @ExcludeMissing fun _promptTokens() = promptTokens + @JsonProperty("prompt_tokens") + @ExcludeMissing + fun _promptTokens(): JsonField = promptTokens /** - * The number of tokens in the completion generated by the model (only set if this is an LLM - * span) + * Returns the raw JSON value of [start]. + * + * Unlike [start], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun _completionTokens() = completionTokens + @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start + + /** + * Returns the raw JSON value of [tokens]. + * + * Unlike [tokens], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tokens") @ExcludeMissing fun _tokens(): JsonField = tokens - /** The total number of tokens in the input and output of the project logs event. */ - @JsonProperty("tokens") @ExcludeMissing fun _tokens() = tokens + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Metrics = apply { - if (!validated) { - start() - end() - promptTokens() - completionTokens() - tokens() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metrics && - this.start == other.start && - this.end == other.end && - this.promptTokens == other.promptTokens && - this.completionTokens == other.completionTokens && - this.tokens == other.tokens && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - start, - end, - promptTokens, - completionTokens, - tokens, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Metrics{start=$start, end=$end, promptTokens=$promptTokens, completionTokens=$completionTokens, tokens=$tokens, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metrics]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metrics]. */ + class Builder internal constructor() { - private var start: JsonField = JsonMissing.of() + private var callerFilename: JsonValue = JsonMissing.of() + private var callerFunctionname: JsonValue = JsonMissing.of() + private var callerLineno: JsonValue = JsonMissing.of() + private var completionTokens: JsonField = JsonMissing.of() private var end: JsonField = JsonMissing.of() private var promptTokens: JsonField = JsonMissing.of() - private var completionTokens: JsonField = JsonMissing.of() + private var start: JsonField = JsonMissing.of() private var tokens: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metrics: Metrics) = apply { - this.start = metrics.start - this.end = metrics.end - this.promptTokens = metrics.promptTokens - this.completionTokens = metrics.completionTokens - this.tokens = metrics.tokens - additionalProperties(metrics.additionalProperties) + callerFilename = metrics.callerFilename + callerFunctionname = metrics.callerFunctionname + callerLineno = metrics.callerLineno + completionTokens = metrics.completionTokens + end = metrics.end + promptTokens = metrics.promptTokens + start = metrics.start + tokens = metrics.tokens + additionalProperties = metrics.additionalProperties.toMutableMap() + } + + /** This metric is deprecated */ + fun callerFilename(callerFilename: JsonValue) = apply { + this.callerFilename = callerFilename } + /** This metric is deprecated */ + fun callerFunctionname(callerFunctionname: JsonValue) = apply { + this.callerFunctionname = callerFunctionname + } + + /** This metric is deprecated */ + fun callerLineno(callerLineno: JsonValue) = apply { this.callerLineno = callerLineno } + /** - * A unix timestamp recording when the section of code which produced the project logs - * event started + * The number of tokens in the completion generated by the model (only set if this is an + * LLM span) */ - fun start(start: Double) = start(JsonField.of(start)) + fun completionTokens(completionTokens: Long?) = + completionTokens(JsonField.ofNullable(completionTokens)) /** - * A unix timestamp recording when the section of code which produced the project logs - * event started + * Alias for [Builder.completionTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. */ - @JsonProperty("start") - @ExcludeMissing - fun start(start: JsonField) = apply { this.start = start } + fun completionTokens(completionTokens: Long) = + completionTokens(completionTokens as Long?) /** - * A unix timestamp recording when the section of code which produced the project logs - * event finished + * Sets [Builder.completionTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.completionTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun end(end: Double) = end(JsonField.of(end)) + fun completionTokens(completionTokens: JsonField) = apply { + this.completionTokens = completionTokens + } /** * A unix timestamp recording when the section of code which produced the project logs * event finished */ - @JsonProperty("end") - @ExcludeMissing + fun end(end: Double?) = end(JsonField.ofNullable(end)) + + /** + * Alias for [Builder.end]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun end(end: Double) = end(end as Double?) + + /** + * Sets [Builder.end] to an arbitrary JSON value. + * + * You should usually call [Builder.end] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun end(end: JsonField) = apply { this.end = end } /** * The number of tokens in the prompt used to generate the project logs event (only set * if this is an LLM span) */ - fun promptTokens(promptTokens: Long) = promptTokens(JsonField.of(promptTokens)) + fun promptTokens(promptTokens: Long?) = promptTokens(JsonField.ofNullable(promptTokens)) /** - * The number of tokens in the prompt used to generate the project logs event (only set - * if this is an LLM span) + * Alias for [Builder.promptTokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun promptTokens(promptTokens: Long) = promptTokens(promptTokens as Long?) + + /** + * Sets [Builder.promptTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.promptTokens] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("prompt_tokens") - @ExcludeMissing fun promptTokens(promptTokens: JsonField) = apply { this.promptTokens = promptTokens } /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) + * A unix timestamp recording when the section of code which produced the project logs + * event started */ - fun completionTokens(completionTokens: Long) = - completionTokens(JsonField.of(completionTokens)) + fun start(start: Double?) = start(JsonField.ofNullable(start)) /** - * The number of tokens in the completion generated by the model (only set if this is an - * LLM span) + * Alias for [Builder.start]. + * + * This unboxed primitive overload exists for backwards compatibility. */ - @JsonProperty("completion_tokens") - @ExcludeMissing - fun completionTokens(completionTokens: JsonField) = apply { - this.completionTokens = completionTokens - } + fun start(start: Double) = start(start as Double?) - /** The total number of tokens in the input and output of the project logs event. */ - fun tokens(tokens: Long) = tokens(JsonField.of(tokens)) + /** + * Sets [Builder.start] to an arbitrary JSON value. + * + * You should usually call [Builder.start] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun start(start: JsonField) = apply { this.start = start } /** The total number of tokens in the input and output of the project logs event. */ - @JsonProperty("tokens") - @ExcludeMissing + fun tokens(tokens: Long?) = tokens(JsonField.ofNullable(tokens)) + + /** + * Alias for [Builder.tokens]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun tokens(tokens: Long) = tokens(tokens as Long?) + + /** + * Sets [Builder.tokens] to an arbitrary JSON value. + * + * You should usually call [Builder.tokens] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun tokens(tokens: JsonField) = apply { this.tokens = tokens } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Metrics]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): Metrics = Metrics( - start, + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, end, promptTokens, - completionTokens, + start, tokens, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - } - - /** - * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety - * of signals that help you determine how accurate the outputs are compared to what you expect - * and diagnose failures. For example, a summarization app might have one score that tells you - * how accurate the summary is, and another that measures the word similarity between the - * generated and grouth truth summary. The word similarity score could help you determine - * whether the summarization was covering similar concepts or not. You can use these scores to - * help you sort, filter, and compare logs. - */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Metrics = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + completionTokens() + end() + promptTokens() + start() + tokens() + validated = true + } - fun validate(): Scores = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (completionTokens.asKnown() == null) 0 else 1) + + (if (end.asKnown() == null) 0 else 1) + + (if (promptTokens.asKnown() == null) 0 else 1) + + (if (start.asKnown() == null) 0 else 1) + + (if (tokens.asKnown() == null) 0 else 1) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Scores && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode + return other is Metrics && + callerFilename == other.callerFilename && + callerFunctionname == other.callerFunctionname && + callerLineno == other.callerLineno && + completionTokens == other.completionTokens && + end == other.end && + promptTokens == other.promptTokens && + start == other.start && + tokens == other.tokens && + additionalProperties == other.additionalProperties } - override fun toString() = "Scores{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + private val hashCode: Int by lazy { + Objects.hash( + callerFilename, + callerFunctionname, + callerLineno, + completionTokens, + end, + promptTokens, + start, + tokens, + additionalProperties, + ) } - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = hashCode - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) - } + override fun toString() = + "Metrics{callerFilename=$callerFilename, callerFunctionname=$callerFunctionname, callerLineno=$callerLineno, completionTokens=$completionTokens, end=$end, promptTokens=$promptTokens, start=$start, tokens=$tokens, additionalProperties=$additionalProperties}" } - /** Human-identifying attributes of the span, such as name, type, etc. */ - @JsonDeserialize(builder = SpanAttributes.Builder::class) - @NoAutoDetect - class SpanAttributes + /** + * A dictionary of numeric values (between 0 and 1) to log. The scores should give you a variety + * of signals that help you determine how accurate the outputs are compared to what you expect + * and diagnose failures. For example, a summarization app might have one score that tells you + * how accurate the summary is, and another that measures the word similarity between the + * generated and grouth truth summary. The word similarity score could help you determine + * whether the summarization was covering similar concepts or not. You can use these scores to + * help you sort, filter, and compare logs. + */ + class Scores + @JsonCreator private constructor( - private val name: JsonField, - private val type: JsonField, - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Name of the span, for display purposes only */ - fun name(): String? = name.getNullable("name") - - /** Type of the span, for display purposes only */ - fun type(): Type? = type.getNullable("type") - - /** Name of the span, for display purposes only */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Type of the span, for display purposes only */ - @JsonProperty("type") @ExcludeMissing fun _type() = type - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): SpanAttributes = apply { - if (!validated) { - name() - type() - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SpanAttributes && - this.name == other.name && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - type, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SpanAttributes{name=$name, type=$type, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Scores]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Scores]. */ + class Builder internal constructor() { - private var name: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(spanAttributes: SpanAttributes) = apply { - this.name = spanAttributes.name - this.type = spanAttributes.type - additionalProperties(spanAttributes.additionalProperties) + internal fun from(scores: Scores) = apply { + additionalProperties = scores.additionalProperties.toMutableMap() } - /** Name of the span, for display purposes only */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the span, for display purposes only */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - /** Type of the span, for display purposes only */ - fun type(type: Type) = type(JsonField.of(type)) - - /** Type of the span, for display purposes only */ - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): SpanAttributes = - SpanAttributes( - name, - type, - additionalProperties.toUnmodifiable(), - ) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns an immutable instance of [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Type && this.value == other.value + fun validate(): Scores = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { + validated = true + } - val LLM = Type(JsonField.of("llm")) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - val SCORE = Type(JsonField.of("score")) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - val FUNCTION = Type(JsonField.of("function")) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - val EVAL = Type(JsonField.of("eval")) + return other is Scores && additionalProperties == other.additionalProperties + } - val TASK = Type(JsonField.of("task")) + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - val TOOL = Type(JsonField.of("tool")) + override fun hashCode(): Int = hashCode - fun of(value: String) = Type(JsonField.of(value)) - } + override fun toString() = "Scores{additionalProperties=$additionalProperties}" + } - enum class Known { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - enum class Value { - LLM, - SCORE, - FUNCTION, - EVAL, - TASK, - TOOL, - _UNKNOWN, - } + return other is ProjectLogsEvent && + id == other.id && + _xactId == other._xactId && + created == other.created && + logId == other.logId && + orgId == other.orgId && + projectId == other.projectId && + rootSpanId == other.rootSpanId && + spanId == other.spanId && + context == other.context && + error == other.error && + expected == other.expected && + input == other.input && + isRoot == other.isRoot && + metadata == other.metadata && + metrics == other.metrics && + origin == other.origin && + output == other.output && + scores == other.scores && + spanAttributes == other.spanAttributes && + spanParents == other.spanParents && + tags == other.tags && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - LLM -> Value.LLM - SCORE -> Value.SCORE - FUNCTION -> Value.FUNCTION - EVAL -> Value.EVAL - TASK -> Value.TASK - TOOL -> Value.TOOL - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { + Objects.hash( + id, + _xactId, + created, + logId, + orgId, + projectId, + rootSpanId, + spanId, + context, + error, + expected, + input, + isRoot, + metadata, + metrics, + origin, + output, + scores, + spanAttributes, + spanParents, + tags, + additionalProperties, + ) + } - fun known(): Known = - when (this) { - LLM -> Known.LLM - SCORE -> Known.SCORE - FUNCTION -> Known.FUNCTION - EVAL -> Known.EVAL - TASK -> Known.TASK - TOOL -> Known.TOOL - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "ProjectLogsEvent{id=$id, _xactId=$_xactId, created=$created, logId=$logId, orgId=$orgId, projectId=$projectId, rootSpanId=$rootSpanId, spanId=$spanId, context=$context, error=$error, expected=$expected, input=$input, isRoot=$isRoot, metadata=$metadata, metrics=$metrics, origin=$origin, output=$output, scores=$scores, spanAttributes=$spanAttributes, spanParents=$spanParents, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectRetrieveParams.kt index fb0a2f2f..bf1e158d 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectRetrieveParams.kt @@ -2,125 +2,188 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a project object by its id */ class ProjectRetrieveParams -constructor( - private val projectId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val projectId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun projectId(): String = projectId + /** Project id */ + fun projectId(): String? = projectId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ProjectRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var projectId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(projectRetrieveParams: ProjectRetrieveParams) = apply { + projectId = projectRetrieveParams.projectId + additionalHeaders = projectRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = projectRetrieveParams.additionalQueryParams.toBuilder() } - return other is ProjectRetrieveParams && - this.projectId == other.projectId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Project id */ + fun projectId(projectId: String?) = apply { this.projectId = projectId } - override fun hashCode(): Int { - return Objects.hash( - projectId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "ProjectRetrieveParams{projectId=$projectId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var projectId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(projectRetrieveParams: ProjectRetrieveParams) = apply { - this.projectId = projectRetrieveParams.projectId - additionalQueryParams(projectRetrieveParams.additionalQueryParams) - additionalHeaders(projectRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ProjectRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectRetrieveParams = ProjectRetrieveParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + projectId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectId ?: "" + 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 ProjectRetrieveParams && + projectId == other.projectId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(projectId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectRetrieveParams{projectId=$projectId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScore.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScore.kt index 5a1c7a57..1a4c6450 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScore.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScore.kt @@ -8,12 +8,14 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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 @@ -23,452 +25,693 @@ 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.util.Collections import java.util.Objects /** A project score is a user-configured score, which can be manually-labeled through the UI */ -@JsonDeserialize(builder = ProjectScore.Builder::class) -@NoAutoDetect class ProjectScore +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val projectId: JsonField, - private val userId: JsonField, - private val created: JsonField, private val name: JsonField, - private val description: JsonField, + private val projectId: JsonField, private val scoreType: JsonField, + private val userId: JsonField, private val categories: JsonField, private val config: JsonField, + private val created: JsonField, + private val description: JsonField, private val position: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the project score */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("score_type") + @ExcludeMissing + scoreType: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + @JsonProperty("categories") + @ExcludeMissing + categories: JsonField = JsonMissing.of(), + @JsonProperty("config") + @ExcludeMissing + config: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("position") @ExcludeMissing position: JsonField = JsonMissing.of(), + ) : this( + id, + name, + projectId, + scoreType, + userId, + categories, + config, + created, + description, + position, + mutableMapOf(), + ) + + /** + * Unique identifier for the project score + * + * @throws BraintrustInvalidDataException 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") - /** Unique identifier for the project that the project score belongs under */ - fun projectId(): String = projectId.getRequired("project_id") - - fun userId(): String = userId.getRequired("user_id") - - /** Date of project score creation */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** Name of the project score */ + /** + * Name of the project score + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** Textual description of the project score */ - fun description(): String? = description.getNullable("description") + /** + * Unique identifier for the project that the project score belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** The type of the configured score */ + /** + * The type of the configured score + * + * @throws BraintrustInvalidDataException 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 scoreType(): ProjectScoreType = scoreType.getRequired("score_type") + /** + * @throws BraintrustInvalidDataException 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 userId(): String = userId.getRequired("user_id") + + /** + * For categorical-type project scores, the list of all categories + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun categories(): Categories? = categories.getNullable("categories") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun config(): ProjectScoreConfig? = config.getNullable("config") - /** An optional LexoRank-based string that sets the sort position for the score in the UI */ - fun position(): String? = position.getNullable("position") - - /** Unique identifier for the project score */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Unique identifier for the project that the project score belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId - - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId - - /** Date of project score creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Name of the project score */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Textual description of the project score */ - @JsonProperty("description") @ExcludeMissing fun _description() = description - - /** The type of the configured score */ - @JsonProperty("score_type") @ExcludeMissing fun _scoreType() = scoreType + /** + * Date of project score creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") - @JsonProperty("categories") @ExcludeMissing fun _categories() = categories + /** + * Textual description of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - @JsonProperty("config") @ExcludeMissing fun _config() = config + /** + * An optional LexoRank-based string that sets the sort position for the score in the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun position(): String? = position.getNullable("position") - /** An optional LexoRank-based string that sets the sort position for the score in the UI */ - @JsonProperty("position") @ExcludeMissing fun _position() = position + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [scoreType]. + * + * Unlike [scoreType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("score_type") + @ExcludeMissing + fun _scoreType(): JsonField = scoreType + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + /** + * Returns the raw JSON value of [categories]. + * + * Unlike [categories], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("categories") + @ExcludeMissing + fun _categories(): JsonField = categories + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("config") @ExcludeMissing fun _config(): JsonField = config + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * 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 [position]. + * + * Unlike [position], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("position") @ExcludeMissing fun _position(): JsonField = position + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ProjectScore = apply { - if (!validated) { - id() - projectId() - userId() - created() - name() - description() - scoreType() - categories() - config()?.validate() - position() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectScore && - this.id == other.id && - this.projectId == other.projectId && - this.userId == other.userId && - this.created == other.created && - this.name == other.name && - this.description == other.description && - this.scoreType == other.scoreType && - this.categories == other.categories && - this.config == other.config && - this.position == other.position && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - projectId, - userId, - created, - name, - description, - scoreType, - categories, - config, - position, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ProjectScore{id=$id, projectId=$projectId, userId=$userId, created=$created, name=$name, description=$description, scoreType=$scoreType, categories=$categories, config=$config, position=$position, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ProjectScore]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .scoreType() + * .userId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ProjectScore]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() - private var created: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() - private var scoreType: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var projectId: JsonField? = null + private var scoreType: JsonField? = null + private var userId: JsonField? = null private var categories: JsonField = JsonMissing.of() private var config: JsonField = JsonMissing.of() + private var created: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() private var position: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectScore: ProjectScore) = apply { - this.id = projectScore.id - this.projectId = projectScore.projectId - this.userId = projectScore.userId - this.created = projectScore.created - this.name = projectScore.name - this.description = projectScore.description - this.scoreType = projectScore.scoreType - this.categories = projectScore.categories - this.config = projectScore.config - this.position = projectScore.position - additionalProperties(projectScore.additionalProperties) + id = projectScore.id + name = projectScore.name + projectId = projectScore.projectId + scoreType = projectScore.scoreType + userId = projectScore.userId + categories = projectScore.categories + config = projectScore.config + created = projectScore.created + description = projectScore.description + position = projectScore.position + additionalProperties = projectScore.additionalProperties.toMutableMap() } /** Unique identifier for the project score */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the project score */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** Unique identifier for the project that the project score belongs under */ - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - /** Unique identifier for the project that the project score belongs under */ - @JsonProperty("project_id") - @ExcludeMissing - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } - - fun userId(userId: String) = userId(JsonField.of(userId)) - - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } - - /** Date of project score creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - - /** Date of project score creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } + /** + * 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 } /** Name of the project score */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the project score */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } - /** Textual description of the project score */ - fun description(description: String) = description(JsonField.of(description)) + /** Unique identifier for the project that the project score belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Textual description of the project score */ - @JsonProperty("description") - @ExcludeMissing - fun description(description: JsonField) = apply { this.description = description } + /** + * 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 } /** The type of the configured score */ fun scoreType(scoreType: ProjectScoreType) = scoreType(JsonField.of(scoreType)) - /** The type of the configured score */ - @JsonProperty("score_type") - @ExcludeMissing + /** + * Sets [Builder.scoreType] to an arbitrary JSON value. + * + * You should usually call [Builder.scoreType] with a well-typed [ProjectScoreType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun scoreType(scoreType: JsonField) = apply { this.scoreType = scoreType } - fun categories(categories: Categories) = categories(JsonField.of(categories)) + fun userId(userId: String) = userId(JsonField.of(userId)) - @JsonProperty("categories") - @ExcludeMissing + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } + + /** For categorical-type project scores, the list of all categories */ + fun categories(categories: Categories?) = categories(JsonField.ofNullable(categories)) + + /** + * Sets [Builder.categories] to an arbitrary JSON value. + * + * You should usually call [Builder.categories] with a well-typed [Categories] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun categories(categories: JsonField) = apply { this.categories = categories } - fun config(config: ProjectScoreConfig) = config(JsonField.of(config)) + /** Alias for calling [categories] with `Categories.ofCategorical(categorical)`. */ + fun categoriesOfCategorical(categorical: List) = + categories(Categories.ofCategorical(categorical)) - @JsonProperty("config") - @ExcludeMissing + /** Alias for calling [categories] with `Categories.ofWeighted(weighted)`. */ + fun categories(weighted: Categories.Weighted) = categories(Categories.ofWeighted(weighted)) + + /** Alias for calling [categories] with `Categories.ofMinimum(minimum)`. */ + fun categoriesOfMinimum(minimum: List) = categories(Categories.ofMinimum(minimum)) + + fun config(config: ProjectScoreConfig?) = config(JsonField.ofNullable(config)) + + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [ProjectScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun config(config: JsonField) = apply { this.config = config } - /** An optional LexoRank-based string that sets the sort position for the score in the UI */ - fun position(position: String) = position(JsonField.of(position)) + /** Date of project score creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } + + /** Textual description of the project score */ + fun description(description: String?) = description(JsonField.ofNullable(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 } /** An optional LexoRank-based string that sets the sort position for the score in the UI */ - @JsonProperty("position") - @ExcludeMissing + fun position(position: String?) = position(JsonField.ofNullable(position)) + + /** + * Sets [Builder.position] to an arbitrary JSON value. + * + * You should usually call [Builder.position] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun position(position: JsonField) = apply { this.position = position } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ProjectScore]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .scoreType() + * .userId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ProjectScore = ProjectScore( - id, - projectId, - userId, - created, - name, - description, - scoreType, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("scoreType", scoreType), + checkRequired("userId", userId), categories, config, + created, + description, position, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): ProjectScore = apply { + if (validated) { + return@apply + } + + id() + name() + projectId() + scoreType().validate() + userId() + categories()?.validate() + config()?.validate() + created() + description() + position() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (scoreType.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + + (categories.asKnown()?.validity() ?: 0) + + (config.asKnown()?.validity() ?: 0) + + (if (created.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (if (position.asKnown() == null) 0 else 1) + + /** For categorical-type project scores, the list of all categories */ @JsonDeserialize(using = Categories.Deserializer::class) @JsonSerialize(using = Categories.Serializer::class) class Categories private constructor( - private val projectScoreCategories: List? = null, + private val categorical: List? = null, private val weighted: Weighted? = null, - private val strings: List? = null, - private val nullableVariant: NullableVariant? = null, + private val minimum: List? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - /** For categorical-type project scores, the list of all categories */ - fun projectScoreCategories(): List? = projectScoreCategories + fun categorical(): List? = categorical + /** For weighted-type project scores, the weights of each score */ fun weighted(): Weighted? = weighted - /** For minimum-type project scores, the list of included scores */ - fun strings(): List? = strings - fun nullableVariant(): NullableVariant? = nullableVariant + /** For minimum-type project scores, the list of included scores */ + fun minimum(): List? = minimum - fun isProjectScoreCategories(): Boolean = projectScoreCategories != null + fun isCategorical(): Boolean = categorical != null fun isWeighted(): Boolean = weighted != null - fun isStrings(): Boolean = strings != null - - fun isNullableVariant(): Boolean = nullableVariant != null + fun isMinimum(): Boolean = minimum != null - fun asProjectScoreCategories(): List = - projectScoreCategories.getOrThrow("projectScoreCategories") + /** For categorical-type project scores, the list of all categories */ + fun asCategorical(): List = categorical.getOrThrow("categorical") + /** For weighted-type project scores, the weights of each score */ fun asWeighted(): Weighted = weighted.getOrThrow("weighted") - fun asStrings(): List = strings.getOrThrow("strings") - - fun asNullableVariant(): NullableVariant = nullableVariant.getOrThrow("nullableVariant") + /** For minimum-type project scores, the list of included scores */ + fun asMinimum(): List = minimum.getOrThrow("minimum") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - projectScoreCategories != null -> - visitor.visitProjectScoreCategories(projectScoreCategories) + fun accept(visitor: Visitor): T = + when { + categorical != null -> visitor.visitCategorical(categorical) weighted != null -> visitor.visitWeighted(weighted) - strings != null -> visitor.visitStrings(strings) - nullableVariant != null -> visitor.visitNullableVariant(nullableVariant) + minimum != null -> visitor.visitMinimum(minimum) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Categories = apply { - if (!validated) { - if ( - projectScoreCategories == null && - weighted == null && - strings == null && - nullableVariant == null - ) { - throw BraintrustInvalidDataException("Unknown Categories: $_json") - } - projectScoreCategories?.forEach { it.validate() } - weighted?.validate() - nullableVariant?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitCategorical(categorical: List) { + categorical.forEach { it.validate() } + } + + override fun visitWeighted(weighted: Weighted) { + weighted.validate() + } + + override fun visitMinimum(minimum: List) {} + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitCategorical(categorical: List) = + categorical.sumOf { it.validity().toInt() } + + override fun visitWeighted(weighted: Weighted) = weighted.validity() + + override fun visitMinimum(minimum: List) = minimum.size + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is Categories && - this.projectScoreCategories == other.projectScoreCategories && - this.weighted == other.weighted && - this.strings == other.strings && - this.nullableVariant == other.nullableVariant + categorical == other.categorical && + weighted == other.weighted && + minimum == other.minimum } - override fun hashCode(): Int { - return Objects.hash( - projectScoreCategories, - weighted, - strings, - nullableVariant, - ) - } + override fun hashCode(): Int = Objects.hash(categorical, weighted, minimum) - override fun toString(): String { - return when { - projectScoreCategories != null -> - "Categories{projectScoreCategories=$projectScoreCategories}" + override fun toString(): String = + when { + categorical != null -> "Categories{categorical=$categorical}" weighted != null -> "Categories{weighted=$weighted}" - strings != null -> "Categories{strings=$strings}" - nullableVariant != null -> "Categories{nullableVariant=$nullableVariant}" + minimum != null -> "Categories{minimum=$minimum}" _json != null -> "Categories{_unknown=$_json}" else -> throw IllegalStateException("Invalid Categories") } - } companion object { - fun ofProjectScoreCategories(projectScoreCategories: List) = - Categories(projectScoreCategories = projectScoreCategories) + /** For categorical-type project scores, the list of all categories */ + fun ofCategorical(categorical: List) = + Categories(categorical = categorical.toImmutable()) + /** For weighted-type project scores, the weights of each score */ fun ofWeighted(weighted: Weighted) = Categories(weighted = weighted) - fun ofStrings(strings: List) = Categories(strings = strings) - - fun ofNullableVariant(nullableVariant: NullableVariant) = - Categories(nullableVariant = nullableVariant) + /** For minimum-type project scores, the list of included scores */ + fun ofMinimum(minimum: List) = Categories(minimum = minimum.toImmutable()) } + /** + * An interface that defines how to map each variant of [Categories] to a value of type [T]. + */ interface Visitor { - fun visitProjectScoreCategories(projectScoreCategories: List): T + /** For categorical-type project scores, the list of all categories */ + fun visitCategorical(categorical: List): T + /** For weighted-type project scores, the weights of each score */ fun visitWeighted(weighted: Weighted): T - fun visitStrings(strings: List): T - - fun visitNullableVariant(nullableVariant: NullableVariant): T - + /** For minimum-type project scores, the list of included scores */ + fun visitMinimum(minimum: List): T + + /** + * Maps an unknown variant of [Categories] to a value of type [T]. + * + * An instance of [Categories] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Categories: $json") } } - class Deserializer : BaseDeserializer(Categories::class) { + internal class Deserializer : BaseDeserializer(Categories::class) { override fun ObjectCodec.deserialize(node: JsonNode): Categories { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef>()) { - it.forEach { it.validate() } - } - ?.let { - return Categories(projectScoreCategories = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(weighted = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Categories(strings = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(nullableVariant = it, _json = json) - } - return Categories(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Categories(weighted = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>()) + ?.let { Categories(categorical = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef>())?.let { + Categories(minimum = 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 -> Categories(_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() + } } } - class Serializer : BaseSerializer(Categories::class) { + internal class Serializer : BaseSerializer(Categories::class) { override fun serialize( value: Categories, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.projectScoreCategories != null -> - generator.writeObject(value.projectScoreCategories) + value.categorical != null -> generator.writeObject(value.categorical) value.weighted != null -> generator.writeObject(value.weighted) - value.strings != null -> generator.writeObject(value.strings) - value.nullableVariant != null -> generator.writeObject(value.nullableVariant) + value.minimum != null -> generator.writeObject(value.minimum) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Categories") } @@ -476,67 +719,41 @@ private constructor( } /** For weighted-type project scores, the weights of each score */ - @JsonDeserialize(builder = Weighted.Builder::class) - @NoAutoDetect class Weighted + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Weighted = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Weighted && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Weighted{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Weighted]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Weighted]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(weighted: Weighted) = apply { - additionalProperties(weighted.additionalProperties) + additionalProperties = weighted.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -544,82 +761,102 @@ private constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Weighted = Weighted(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - @JsonDeserialize(builder = NullableVariant.Builder::class) - @NoAutoDetect - class NullableVariant - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Weighted]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Weighted = Weighted(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Weighted = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): NullableVariant = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 NullableVariant && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode + return other is Weighted && additionalProperties == other.additionalProperties } - override fun toString() = "NullableVariant{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - class Builder { + override fun hashCode(): Int = hashCode - private var additionalProperties: MutableMap = mutableMapOf() + override fun toString() = "Weighted{additionalProperties=$additionalProperties}" + } + } - internal fun from(nullableVariant: NullableVariant) = apply { - additionalProperties(nullableVariant.additionalProperties) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + return other is ProjectScore && + id == other.id && + name == other.name && + projectId == other.projectId && + scoreType == other.scoreType && + userId == other.userId && + categories == other.categories && + config == other.config && + created == other.created && + description == other.description && + position == other.position && + additionalProperties == other.additionalProperties + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + projectId, + scoreType, + userId, + categories, + config, + created, + description, + position, + additionalProperties, + ) + } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = hashCode - fun build(): NullableVariant = - NullableVariant(additionalProperties.toUnmodifiable()) - } - } - } + override fun toString() = + "ProjectScore{id=$id, name=$name, projectId=$projectId, scoreType=$scoreType, userId=$userId, categories=$categories, config=$config, created=$created, description=$description, position=$position, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCategory.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCategory.kt index ef0de1ca..b29ae4e6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCategory.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCategory.kt @@ -6,132 +6,204 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** For categorical-type project scores, defines a single category */ -@JsonDeserialize(builder = ProjectScoreCategory.Builder::class) -@NoAutoDetect class ProjectScoreCategory +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val name: JsonField, private val value: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Name of the category */ + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(), + ) : this(name, value, mutableMapOf()) + + /** + * Name of the category + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** Numerical value of the category. Must be between 0 and 1, inclusive */ + /** + * Numerical value of the category. Must be between 0 and 1, inclusive + * + * @throws BraintrustInvalidDataException 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(): Double = value.getRequired("value") - /** Name of the category */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Numerical value of the category. Must be between 0 and 1, inclusive */ - @JsonProperty("value") @ExcludeMissing fun _value() = value + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [value]. + * + * Unlike [value], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ProjectScoreCategory = apply { - if (!validated) { - name() - value() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectScoreCategory && - this.name == other.name && - this.value == other.value && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - value, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ProjectScoreCategory{name=$name, value=$value, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ProjectScoreCategory]. + * + * The following fields are required: + * ```kotlin + * .name() + * .value() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ProjectScoreCategory]. */ + class Builder internal constructor() { - private var name: JsonField = JsonMissing.of() - private var value: JsonField = JsonMissing.of() + private var name: JsonField? = null + private var value: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectScoreCategory: ProjectScoreCategory) = apply { - this.name = projectScoreCategory.name - this.value = projectScoreCategory.value - additionalProperties(projectScoreCategory.additionalProperties) + name = projectScoreCategory.name + value = projectScoreCategory.value + additionalProperties = projectScoreCategory.additionalProperties.toMutableMap() } /** Name of the category */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the category */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } /** Numerical value of the category. Must be between 0 and 1, inclusive */ fun value(value: Double) = value(JsonField.of(value)) - /** Numerical value of the category. Must be between 0 and 1, inclusive */ - @JsonProperty("value") - @ExcludeMissing + /** + * Sets [Builder.value] to an arbitrary JSON value. + * + * You should usually call [Builder.value] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun value(value: JsonField) = apply { this.value = value } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ProjectScoreCategory]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .value() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ProjectScoreCategory = ProjectScoreCategory( - name, - value, - additionalProperties.toUnmodifiable(), + checkRequired("name", name), + checkRequired("value", value), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): ProjectScoreCategory = apply { + if (validated) { + return@apply + } + + name() + value() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (if (value.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectScoreCategory && + name == other.name && + value == other.value && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, value, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectScoreCategory{name=$name, value=$value, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreConfig.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreConfig.kt index 71f1fbc8..dddde51a 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreConfig.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreConfig.kt @@ -2,200 +2,236 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ProjectScoreConfig.Builder::class) -@NoAutoDetect class ProjectScoreConfig +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val destination: JsonField, private val multiSelect: JsonField, - private val destination: JsonField, private val online: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("destination") + @ExcludeMissing + destination: JsonField = JsonMissing.of(), + @JsonProperty("multi_select") + @ExcludeMissing + multiSelect: JsonField = JsonMissing.of(), + @JsonProperty("online") + @ExcludeMissing + online: JsonField = JsonMissing.of(), + ) : this(destination, multiSelect, online, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun destination(): String? = destination.getNullable("destination") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun multiSelect(): Boolean? = multiSelect.getNullable("multi_select") - fun destination(): Destination? = destination.getNullable("destination") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun online(): OnlineScoreConfig? = online.getNullable("online") - @JsonProperty("multi_select") @ExcludeMissing fun _multiSelect() = multiSelect - - @JsonProperty("destination") @ExcludeMissing fun _destination() = destination - - @JsonProperty("online") @ExcludeMissing fun _online() = online + /** + * Returns the raw JSON value of [destination]. + * + * Unlike [destination], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("destination") @ExcludeMissing fun _destination(): JsonField = destination + + /** + * Returns the raw JSON value of [multiSelect]. + * + * Unlike [multiSelect], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("multi_select") + @ExcludeMissing + fun _multiSelect(): JsonField = multiSelect + + /** + * Returns the raw JSON value of [online]. + * + * Unlike [online], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("online") @ExcludeMissing fun _online(): JsonField = online + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ProjectScoreConfig = apply { - if (!validated) { - multiSelect() - destination() - online()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectScoreConfig && - this.multiSelect == other.multiSelect && - this.destination == other.destination && - this.online == other.online && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - multiSelect, - destination, - online, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ProjectScoreConfig{multiSelect=$multiSelect, destination=$destination, online=$online, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [ProjectScoreConfig]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ProjectScoreConfig]. */ + class Builder internal constructor() { + private var destination: JsonField = JsonMissing.of() private var multiSelect: JsonField = JsonMissing.of() - private var destination: JsonField = JsonMissing.of() private var online: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectScoreConfig: ProjectScoreConfig) = apply { - this.multiSelect = projectScoreConfig.multiSelect - this.destination = projectScoreConfig.destination - this.online = projectScoreConfig.online - additionalProperties(projectScoreConfig.additionalProperties) + destination = projectScoreConfig.destination + multiSelect = projectScoreConfig.multiSelect + online = projectScoreConfig.online + additionalProperties = projectScoreConfig.additionalProperties.toMutableMap() } - fun multiSelect(multiSelect: Boolean) = multiSelect(JsonField.of(multiSelect)) - - @JsonProperty("multi_select") - @ExcludeMissing + fun destination(destination: String?) = destination(JsonField.ofNullable(destination)) + + /** + * Sets [Builder.destination] to an arbitrary JSON value. + * + * You should usually call [Builder.destination] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun destination(destination: JsonField) = apply { this.destination = destination } + + fun multiSelect(multiSelect: Boolean?) = multiSelect(JsonField.ofNullable(multiSelect)) + + /** + * Alias for [Builder.multiSelect]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun multiSelect(multiSelect: Boolean) = multiSelect(multiSelect as Boolean?) + + /** + * Sets [Builder.multiSelect] to an arbitrary JSON value. + * + * You should usually call [Builder.multiSelect] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun multiSelect(multiSelect: JsonField) = apply { this.multiSelect = multiSelect } - fun destination(destination: Destination) = destination(JsonField.of(destination)) - - @JsonProperty("destination") - @ExcludeMissing - fun destination(destination: JsonField) = apply { - this.destination = destination - } + fun online(online: OnlineScoreConfig?) = online(JsonField.ofNullable(online)) - fun online(online: OnlineScoreConfig) = online(JsonField.of(online)) - - @JsonProperty("online") - @ExcludeMissing + /** + * Sets [Builder.online] to an arbitrary JSON value. + * + * You should usually call [Builder.online] with a well-typed [OnlineScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun online(online: JsonField) = apply { this.online = online } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ProjectScoreConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectScoreConfig = ProjectScoreConfig( - multiSelect, destination, + multiSelect, online, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Destination - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Destination && this.value == other.value + fun validate(): ProjectScoreConfig = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val EXPECTED = Destination(JsonField.of("expected")) + destination() + multiSelect() + online()?.validate() + validated = true + } - fun of(value: String) = Destination(JsonField.of(value)) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - enum class Known { - EXPECTED, - } + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (destination.asKnown() == null) 0 else 1) + + (if (multiSelect.asKnown() == null) 0 else 1) + + (online.asKnown()?.validity() ?: 0) - enum class Value { - EXPECTED, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - EXPECTED -> Value.EXPECTED - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - EXPECTED -> Known.EXPECTED - else -> throw BraintrustInvalidDataException("Unknown Destination: $value") - } + return other is ProjectScoreConfig && + destination == other.destination && + multiSelect == other.multiSelect && + online == other.online && + additionalProperties == other.additionalProperties + } - fun asString(): String = _value().asStringOrThrow() + private val hashCode: Int by lazy { + Objects.hash(destination, multiSelect, online, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectScoreConfig{destination=$destination, multiSelect=$multiSelect, online=$online, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParams.kt index 5822b91c..b2dfcbd3 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParams.kt @@ -5,13 +5,20 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.BaseDeserializer import com.braintrustdata.api.core.BaseSerializer import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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 @@ -20,540 +27,971 @@ 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 +/** + * Create a new project_score. If there is an existing project_score in the project with the same + * name as the one specified in the request, will return the existing project_score unmodified + */ class ProjectScoreCreateParams -constructor( - private val name: String, - private val projectId: String, - private val scoreType: ProjectScoreType, - private val categories: Categories?, - private val config: ProjectScoreConfig?, - private val description: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun projectId(): String = projectId - - fun scoreType(): ProjectScoreType = scoreType - - fun categories(): Categories? = categories - - fun config(): ProjectScoreConfig? = config - - fun description(): String? = description - - internal fun getBody(): ProjectScoreCreateBody { - return ProjectScoreCreateBody( - name, - projectId, - scoreType, - categories, - config, - description, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the project score + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the project score belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * The type of the configured score + * + * @throws BraintrustInvalidDataException 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 scoreType(): ProjectScoreType = body.scoreType() + + /** + * For categorical-type project scores, the list of all categories + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun categories(): Categories? = body.categories() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun config(): ProjectScoreConfig? = body.config() + + /** + * Textual description of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [scoreType]. + * + * Unlike [scoreType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _scoreType(): JsonField = body._scoreType() + + /** + * Returns the raw JSON value of [categories]. + * + * Unlike [categories], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _categories(): JsonField = body._categories() + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _config(): JsonField = body._config() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + 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 [ProjectScoreCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectScoreCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - /** A project score is a user-configured score, which can be manually-labeled through the UI */ - @JsonDeserialize(builder = ProjectScoreCreateBody.Builder::class) - @NoAutoDetect - class ProjectScoreCreateBody - internal constructor( - private val name: String?, - private val projectId: String?, - private val scoreType: ProjectScoreType?, - private val categories: Categories?, - private val config: ProjectScoreConfig?, - private val description: String?, - private val additionalProperties: Map, - ) { + internal fun from(projectScoreCreateParams: ProjectScoreCreateParams) = apply { + body = projectScoreCreateParams.body.toBuilder() + additionalHeaders = projectScoreCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = projectScoreCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [projectId] + * - [scoreType] + * - [categories] + * - [config] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the project score */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the project score belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** The type of the configured score */ - @JsonProperty("score_type") fun scoreType(): ProjectScoreType? = scoreType + fun scoreType(scoreType: ProjectScoreType) = apply { body.scoreType(scoreType) } + + /** + * Sets [Builder.scoreType] to an arbitrary JSON value. + * + * You should usually call [Builder.scoreType] with a well-typed [ProjectScoreType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun scoreType(scoreType: JsonField) = apply { body.scoreType(scoreType) } + + /** For categorical-type project scores, the list of all categories */ + fun categories(categories: Categories?) = apply { body.categories(categories) } + + /** + * Sets [Builder.categories] to an arbitrary JSON value. + * + * You should usually call [Builder.categories] with a well-typed [Categories] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun categories(categories: JsonField) = apply { body.categories(categories) } + + /** Alias for calling [categories] with `Categories.ofCategorical(categorical)`. */ + fun categoriesOfCategorical(categorical: List) = apply { + body.categoriesOfCategorical(categorical) + } + + /** Alias for calling [categories] with `Categories.ofWeighted(weighted)`. */ + fun categories(weighted: Categories.Weighted) = apply { body.categories(weighted) } + + /** Alias for calling [categories] with `Categories.ofMinimum(minimum)`. */ + fun categoriesOfMinimum(minimum: List) = apply { body.categoriesOfMinimum(minimum) } - @JsonProperty("categories") fun categories(): Categories? = categories + fun config(config: ProjectScoreConfig?) = apply { body.config(config) } - @JsonProperty("config") fun config(): ProjectScoreConfig? = config + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [ProjectScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun config(config: JsonField) = apply { body.config(config) } /** Textual description of the project score */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(description) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * 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 { body.description(description) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is ProjectScoreCreateBody && - this.name == other.name && - this.projectId == other.projectId && - this.scoreType == other.scoreType && - this.categories == other.categories && - this.config == other.config && - this.description == other.description && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - projectId, - scoreType, - categories, - config, - description, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "ProjectScoreCreateBody{name=$name, projectId=$projectId, scoreType=$scoreType, categories=$categories, config=$config, description=$description, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var projectId: String? = null - private var scoreType: ProjectScoreType? = null - private var categories: Categories? = null - private var config: ProjectScoreConfig? = null - private var description: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectScoreCreateBody: ProjectScoreCreateBody) = apply { - this.name = projectScoreCreateBody.name - this.projectId = projectScoreCreateBody.projectId - this.scoreType = projectScoreCreateBody.scoreType - this.categories = projectScoreCreateBody.categories - this.config = projectScoreCreateBody.config - this.description = projectScoreCreateBody.description - additionalProperties(projectScoreCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the project score */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Unique identifier for the project that the project score belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The type of the configured score */ - @JsonProperty("score_type") - fun scoreType(scoreType: ProjectScoreType) = apply { this.scoreType = scoreType } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("categories") - fun categories(categories: Categories) = apply { this.categories = categories } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("config") - fun config(config: ProjectScoreConfig) = apply { this.config = config } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** Textual description of the project score */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): ProjectScoreCreateBody = - ProjectScoreCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(scoreType) { "`scoreType` is required but was not set" }, - categories, - config, - description, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ProjectScoreCreateParams && - this.name == other.name && - this.projectId == other.projectId && - this.scoreType == other.scoreType && - this.categories == other.categories && - this.config == other.config && - this.description == other.description && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ProjectScoreCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectScoreCreateParams = + ProjectScoreCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - projectId, - scoreType, - categories, - config, - description, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "ProjectScoreCreateParams{name=$name, projectId=$projectId, scoreType=$scoreType, categories=$categories, config=$config, description=$description, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + /** A project score is a user-configured score, which can be manually-labeled through the UI */ + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val projectId: JsonField, + private val scoreType: JsonField, + private val categories: JsonField, + private val config: JsonField, + private val description: JsonField, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("score_type") + @ExcludeMissing + scoreType: JsonField = JsonMissing.of(), + @JsonProperty("categories") + @ExcludeMissing + categories: JsonField = JsonMissing.of(), + @JsonProperty("config") + @ExcludeMissing + config: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + ) : this(name, projectId, scoreType, categories, config, description, mutableMapOf()) + + /** + * Name of the project score + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the project score belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * The type of the configured score + * + * @throws BraintrustInvalidDataException 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 scoreType(): ProjectScoreType = scoreType.getRequired("score_type") + + /** + * For categorical-type project scores, the list of all categories + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun categories(): Categories? = categories.getNullable("categories") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun config(): ProjectScoreConfig? = config.getNullable("config") + + /** + * Textual description of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [scoreType]. + * + * Unlike [scoreType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("score_type") + @ExcludeMissing + fun _scoreType(): JsonField = scoreType + + /** + * Returns the raw JSON value of [categories]. + * + * Unlike [categories], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("categories") + @ExcludeMissing + fun _categories(): JsonField = categories + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("config") + @ExcludeMissing + fun _config(): JsonField = config + + /** + * 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 + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @NoAutoDetect - class Builder { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var name: String? = null - private var projectId: String? = null - private var scoreType: ProjectScoreType? = null - private var categories: Categories? = null - private var config: ProjectScoreConfig? = null - private var description: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(projectScoreCreateParams: ProjectScoreCreateParams) = apply { - this.name = projectScoreCreateParams.name - this.projectId = projectScoreCreateParams.projectId - this.scoreType = projectScoreCreateParams.scoreType - this.categories = projectScoreCreateParams.categories - this.config = projectScoreCreateParams.config - this.description = projectScoreCreateParams.description - additionalQueryParams(projectScoreCreateParams.additionalQueryParams) - additionalHeaders(projectScoreCreateParams.additionalHeaders) - additionalBodyProperties(projectScoreCreateParams.additionalBodyProperties) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + */ + fun builder() = Builder() } - /** Name of the project score */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Unique identifier for the project that the project score belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var name: JsonField? = null + private var projectId: JsonField? = null + private var scoreType: JsonField? = null + private var categories: JsonField = JsonMissing.of() + private var config: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** The type of the configured score */ - fun scoreType(scoreType: ProjectScoreType) = apply { this.scoreType = scoreType } + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + scoreType = body.scoreType + categories = body.categories + config = body.config + description = body.description + additionalProperties = body.additionalProperties.toMutableMap() + } - /** For categorical-type project scores, the list of all categories */ - fun categories(categories: Categories) = apply { this.categories = categories } + /** Name of the project score */ + fun name(name: String) = name(JsonField.of(name)) - /** For categorical-type project scores, the list of all categories */ - fun projectScoreCategories(projectScoreCategories: List) = apply { - this.categories = Categories.ofProjectScoreCategories(projectScoreCategories) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** For categorical-type project scores, the list of all categories */ - fun categories(weighted: Categories.Weighted) = apply { - this.categories = Categories.ofWeighted(weighted) - } + /** Unique identifier for the project that the project score belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** For categorical-type project scores, the list of all categories */ - fun categories(strings: List) = apply { - this.categories = Categories.ofStrings(strings) - } + /** + * 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 } - /** For categorical-type project scores, the list of all categories */ - fun categories(nullableVariant: Categories.NullableVariant) = apply { - this.categories = Categories.ofNullableVariant(nullableVariant) - } + /** The type of the configured score */ + fun scoreType(scoreType: ProjectScoreType) = scoreType(JsonField.of(scoreType)) + + /** + * Sets [Builder.scoreType] to an arbitrary JSON value. + * + * You should usually call [Builder.scoreType] with a well-typed [ProjectScoreType] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun scoreType(scoreType: JsonField) = apply { + this.scoreType = scoreType + } - fun config(config: ProjectScoreConfig) = apply { this.config = config } + /** For categorical-type project scores, the list of all categories */ + fun categories(categories: Categories?) = categories(JsonField.ofNullable(categories)) + + /** + * Sets [Builder.categories] to an arbitrary JSON value. + * + * You should usually call [Builder.categories] with a well-typed [Categories] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun categories(categories: JsonField) = apply { + this.categories = categories + } - /** Textual description of the project score */ - fun description(description: String) = apply { this.description = description } + /** Alias for calling [categories] with `Categories.ofCategorical(categorical)`. */ + fun categoriesOfCategorical(categorical: List) = + categories(Categories.ofCategorical(categorical)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** Alias for calling [categories] with `Categories.ofWeighted(weighted)`. */ + fun categories(weighted: Categories.Weighted) = + categories(Categories.ofWeighted(weighted)) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Alias for calling [categories] with `Categories.ofMinimum(minimum)`. */ + fun categoriesOfMinimum(minimum: List) = + categories(Categories.ofMinimum(minimum)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun config(config: ProjectScoreConfig?) = config(JsonField.ofNullable(config)) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [ProjectScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun config(config: JsonField) = apply { this.config = config } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** Textual description of the project score */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("scoreType", scoreType), + categories, + config, + description, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + projectId() + scoreType().validate() + categories()?.validate() + config()?.validate() + description() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ProjectScoreCreateParams = - ProjectScoreCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(scoreType) { "`scoreType` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (scoreType.asKnown()?.validity() ?: 0) + + (categories.asKnown()?.validity() ?: 0) + + (config.asKnown()?.validity() ?: 0) + + (if (description.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + projectId == other.projectId && + scoreType == other.scoreType && + categories == other.categories && + config == other.config && + description == other.description && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + name, + projectId, + scoreType, categories, config, description, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, projectId=$projectId, scoreType=$scoreType, categories=$categories, config=$config, description=$description, additionalProperties=$additionalProperties}" } + /** For categorical-type project scores, the list of all categories */ @JsonDeserialize(using = Categories.Deserializer::class) @JsonSerialize(using = Categories.Serializer::class) class Categories private constructor( - private val projectScoreCategories: List? = null, + private val categorical: List? = null, private val weighted: Weighted? = null, - private val strings: List? = null, - private val nullableVariant: NullableVariant? = null, + private val minimum: List? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - /** For categorical-type project scores, the list of all categories */ - fun projectScoreCategories(): List? = projectScoreCategories + fun categorical(): List? = categorical + /** For weighted-type project scores, the weights of each score */ fun weighted(): Weighted? = weighted - /** For minimum-type project scores, the list of included scores */ - fun strings(): List? = strings - fun nullableVariant(): NullableVariant? = nullableVariant + /** For minimum-type project scores, the list of included scores */ + fun minimum(): List? = minimum - fun isProjectScoreCategories(): Boolean = projectScoreCategories != null + fun isCategorical(): Boolean = categorical != null fun isWeighted(): Boolean = weighted != null - fun isStrings(): Boolean = strings != null - - fun isNullableVariant(): Boolean = nullableVariant != null + fun isMinimum(): Boolean = minimum != null - fun asProjectScoreCategories(): List = - projectScoreCategories.getOrThrow("projectScoreCategories") + /** For categorical-type project scores, the list of all categories */ + fun asCategorical(): List = categorical.getOrThrow("categorical") + /** For weighted-type project scores, the weights of each score */ fun asWeighted(): Weighted = weighted.getOrThrow("weighted") - fun asStrings(): List = strings.getOrThrow("strings") - - fun asNullableVariant(): NullableVariant = nullableVariant.getOrThrow("nullableVariant") + /** For minimum-type project scores, the list of included scores */ + fun asMinimum(): List = minimum.getOrThrow("minimum") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - projectScoreCategories != null -> - visitor.visitProjectScoreCategories(projectScoreCategories) + fun accept(visitor: Visitor): T = + when { + categorical != null -> visitor.visitCategorical(categorical) weighted != null -> visitor.visitWeighted(weighted) - strings != null -> visitor.visitStrings(strings) - nullableVariant != null -> visitor.visitNullableVariant(nullableVariant) + minimum != null -> visitor.visitMinimum(minimum) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Categories = apply { - if (!validated) { - if ( - projectScoreCategories == null && - weighted == null && - strings == null && - nullableVariant == null - ) { - throw BraintrustInvalidDataException("Unknown Categories: $_json") - } - projectScoreCategories?.forEach { it.validate() } - weighted?.validate() - nullableVariant?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitCategorical(categorical: List) { + categorical.forEach { it.validate() } + } + + override fun visitWeighted(weighted: Weighted) { + weighted.validate() + } + + override fun visitMinimum(minimum: List) {} + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitCategorical(categorical: List) = + categorical.sumOf { it.validity().toInt() } + + override fun visitWeighted(weighted: Weighted) = weighted.validity() + + override fun visitMinimum(minimum: List) = minimum.size + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is Categories && - this.projectScoreCategories == other.projectScoreCategories && - this.weighted == other.weighted && - this.strings == other.strings && - this.nullableVariant == other.nullableVariant - } - - override fun hashCode(): Int { - return Objects.hash( - projectScoreCategories, - weighted, - strings, - nullableVariant, - ) + categorical == other.categorical && + weighted == other.weighted && + minimum == other.minimum } - override fun toString(): String { - return when { - projectScoreCategories != null -> - "Categories{projectScoreCategories=$projectScoreCategories}" + override fun hashCode(): Int = Objects.hash(categorical, weighted, minimum) + + override fun toString(): String = + when { + categorical != null -> "Categories{categorical=$categorical}" weighted != null -> "Categories{weighted=$weighted}" - strings != null -> "Categories{strings=$strings}" - nullableVariant != null -> "Categories{nullableVariant=$nullableVariant}" + minimum != null -> "Categories{minimum=$minimum}" _json != null -> "Categories{_unknown=$_json}" else -> throw IllegalStateException("Invalid Categories") } - } companion object { - fun ofProjectScoreCategories(projectScoreCategories: List) = - Categories(projectScoreCategories = projectScoreCategories) + /** For categorical-type project scores, the list of all categories */ + fun ofCategorical(categorical: List) = + Categories(categorical = categorical.toImmutable()) + /** For weighted-type project scores, the weights of each score */ fun ofWeighted(weighted: Weighted) = Categories(weighted = weighted) - fun ofStrings(strings: List) = Categories(strings = strings) - - fun ofNullableVariant(nullableVariant: NullableVariant) = - Categories(nullableVariant = nullableVariant) + /** For minimum-type project scores, the list of included scores */ + fun ofMinimum(minimum: List) = Categories(minimum = minimum.toImmutable()) } + /** + * An interface that defines how to map each variant of [Categories] to a value of type [T]. + */ interface Visitor { - fun visitProjectScoreCategories(projectScoreCategories: List): T + /** For categorical-type project scores, the list of all categories */ + fun visitCategorical(categorical: List): T + /** For weighted-type project scores, the weights of each score */ fun visitWeighted(weighted: Weighted): T - fun visitStrings(strings: List): T - - fun visitNullableVariant(nullableVariant: NullableVariant): T - + /** For minimum-type project scores, the list of included scores */ + fun visitMinimum(minimum: List): T + + /** + * Maps an unknown variant of [Categories] to a value of type [T]. + * + * An instance of [Categories] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Categories: $json") } } - class Deserializer : BaseDeserializer(Categories::class) { + internal class Deserializer : BaseDeserializer(Categories::class) { override fun ObjectCodec.deserialize(node: JsonNode): Categories { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef>()) { - it.forEach { it.validate() } - } - ?.let { - return Categories(projectScoreCategories = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(weighted = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Categories(strings = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(nullableVariant = it, _json = json) - } - return Categories(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Categories(weighted = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>()) + ?.let { Categories(categorical = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef>())?.let { + Categories(minimum = 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 -> Categories(_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() + } } } - class Serializer : BaseSerializer(Categories::class) { + internal class Serializer : BaseSerializer(Categories::class) { override fun serialize( value: Categories, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.projectScoreCategories != null -> - generator.writeObject(value.projectScoreCategories) + value.categorical != null -> generator.writeObject(value.categorical) value.weighted != null -> generator.writeObject(value.weighted) - value.strings != null -> generator.writeObject(value.strings) - value.nullableVariant != null -> generator.writeObject(value.nullableVariant) + value.minimum != null -> generator.writeObject(value.minimum) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Categories") } @@ -561,67 +999,41 @@ constructor( } /** For weighted-type project scores, the weights of each score */ - @JsonDeserialize(builder = Weighted.Builder::class) - @NoAutoDetect class Weighted + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Weighted = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Weighted && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Weighted{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Weighted]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Weighted]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(weighted: Weighted) = apply { - additionalProperties(weighted.additionalProperties) + additionalProperties = weighted.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -629,82 +1041,78 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Weighted = Weighted(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - @JsonDeserialize(builder = NullableVariant.Builder::class) - @NoAutoDetect - class NullableVariant - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Weighted]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Weighted = Weighted(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Weighted = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): NullableVariant = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 NullableVariant && - this.additionalProperties == other.additionalProperties + return other is Weighted && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "NullableVariant{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(nullableVariant: NullableVariant) = apply { - additionalProperties(nullableVariant.additionalProperties) - } + override fun toString() = "Weighted{additionalProperties=$additionalProperties}" + } + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + return other is ProjectScoreCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun build(): NullableVariant = - NullableVariant(additionalProperties.toUnmodifiable()) - } - } - } + override fun toString() = + "ProjectScoreCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParams.kt index 43d18046..d51c87da 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParams.kt @@ -3,138 +3,167 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a project_score object by its id */ class ProjectScoreDeleteParams -constructor( - private val projectScoreId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val projectScoreId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun projectScoreId(): String = projectScoreId + /** ProjectScore id */ + fun projectScoreId(): String? = projectScoreId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectScoreId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ProjectScoreDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectScoreDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectScoreDeleteParams]. */ + class Builder internal constructor() { + + private var projectScoreId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalHeaders(): Map> = additionalHeaders + internal fun from(projectScoreDeleteParams: ProjectScoreDeleteParams) = apply { + projectScoreId = projectScoreDeleteParams.projectScoreId + additionalHeaders = projectScoreDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = projectScoreDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + projectScoreDeleteParams.additionalBodyProperties.toMutableMap() + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + /** ProjectScore id */ + fun projectScoreId(projectScoreId: String?) = apply { this.projectScoreId = projectScoreId } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ProjectScoreDeleteParams && - this.projectScoreId == other.projectScoreId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - projectScoreId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "ProjectScoreDeleteParams{projectScoreId=$projectScoreId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var projectScoreId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(projectScoreDeleteParams: ProjectScoreDeleteParams) = apply { - this.projectScoreId = projectScoreDeleteParams.projectScoreId - additionalQueryParams(projectScoreDeleteParams.additionalQueryParams) - additionalHeaders(projectScoreDeleteParams.additionalHeaders) - additionalBodyProperties(projectScoreDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** ProjectScore id */ - fun projectScoreId(projectScoreId: String) = apply { this.projectScoreId = projectScoreId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +171,60 @@ constructor( 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 [ProjectScoreDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectScoreDeleteParams = ProjectScoreDeleteParams( - checkNotNull(projectScoreId) { "`projectScoreId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + projectScoreId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectScoreId ?: "" + 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 ProjectScoreDeleteParams && + projectScoreId == other.projectScoreId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash( + projectScoreId, + additionalHeaders, + additionalQueryParams, + additionalBodyProperties, + ) + + override fun toString() = + "ProjectScoreDeleteParams{projectScoreId=$projectScoreId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPage.kt index 50e0ca14..1b7c59f0 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPage.kt @@ -2,182 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.ProjectScoreService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see ProjectScoreService.list */ class ProjectScoreListPage private constructor( - private val projectScoresService: ProjectScoreService, + private val service: ProjectScoreService, private val params: ProjectScoreListParams, - private val response: Response, -) { + private val response: ProjectScoreListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [ProjectScoreListPageResponse], but gracefully handles missing data. + * + * @see ProjectScoreListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectScoreListPage && - this.projectScoresService == other.projectScoresService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - projectScoresService, - params, - response, - ) - } - - override fun toString() = - "ProjectScoreListPage{projectScoresService=$projectScoresService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ProjectScoreListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ProjectScoreListParams.builder() - .from(params) - .endingBefore(objects().first().id()) - .build() + fun nextPageParams(): ProjectScoreListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ProjectScoreListParams.builder() - .from(params) - .startingAfter(objects().last().id()) - .build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): ProjectScoreListPage? { - return getNextPageParams()?.let { projectScoresService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - projectScoresService: ProjectScoreService, - params: ProjectScoreListParams, - response: Response - ) = - ProjectScoreListPage( - projectScoresService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): ProjectScoreListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ProjectScoreListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ProjectScoreListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ProjectScoreListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ProjectScoreListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ProjectScoreService? = null + private var params: ProjectScoreListParams? = null + private var response: ProjectScoreListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(projectScoreListPage: ProjectScoreListPage) = apply { + service = projectScoreListPage.service + params = projectScoreListPage.params + response = projectScoreListPage.response } - override fun toString() = - "ProjectScoreListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ProjectScoreService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ProjectScoreListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ProjectScoreListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ProjectScoreListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectScoreListPage = + ProjectScoreListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ProjectScoreListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ProjectScoreListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ProjectScoreListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPageAsync.kt index 66f2aa30..214aa530 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPageAsync.kt @@ -2,184 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.ProjectScoreServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see ProjectScoreServiceAsync.list */ class ProjectScoreListPageAsync private constructor( - private val projectScoresService: ProjectScoreServiceAsync, + private val service: ProjectScoreServiceAsync, private val params: ProjectScoreListParams, - private val response: Response, -) { + private val response: ProjectScoreListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [ProjectScoreListPageResponse], but gracefully handles missing data. + * + * @see ProjectScoreListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectScoreListPageAsync && - this.projectScoresService == other.projectScoresService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - projectScoresService, - params, - response, - ) - } - - override fun toString() = - "ProjectScoreListPageAsync{projectScoresService=$projectScoresService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ProjectScoreListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ProjectScoreListParams.builder() - .from(params) - .endingBefore(objects().first().id()) - .build() + fun nextPageParams(): ProjectScoreListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ProjectScoreListParams.builder() - .from(params) - .startingAfter(objects().last().id()) - .build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): ProjectScoreListPageAsync? { - return getNextPageParams()?.let { projectScoresService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - projectScoresService: ProjectScoreServiceAsync, - params: ProjectScoreListParams, - response: Response - ) = - ProjectScoreListPageAsync( - projectScoresService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): ProjectScoreListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ProjectScoreListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ProjectScoreListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ProjectScoreListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ProjectScoreListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ProjectScoreServiceAsync? = null + private var params: ProjectScoreListParams? = null + private var response: ProjectScoreListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(projectScoreListPageAsync: ProjectScoreListPageAsync) = apply { + service = projectScoreListPageAsync.service + params = projectScoreListPageAsync.params + response = projectScoreListPageAsync.response } - override fun toString() = - "ProjectScoreListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ProjectScoreServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ProjectScoreListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ProjectScoreListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ProjectScoreListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectScoreListPageAsync = + ProjectScoreListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ProjectScoreListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ProjectScoreListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ProjectScoreListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPageResponse.kt new file mode 100644 index 00000000..76bf16b4 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 ProjectScoreListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of project_score objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [ProjectScoreListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ProjectScoreListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(projectScoreListPageResponse: ProjectScoreListPageResponse) = apply { + objects = projectScoreListPageResponse.objects.map { it.toMutableList() } + additionalProperties = projectScoreListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of project_score objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [ProjectScore] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: ProjectScore) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [ProjectScoreListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectScoreListPageResponse = + ProjectScoreListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ProjectScoreListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectScoreListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectScoreListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListParams.kt index ed065003..6810c913 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all project_scores. The project_scores are sorted by creation date, with the most + * recently-created project_scores coming first + */ class ProjectScoreListParams -constructor( +private constructor( private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, @@ -30,96 +24,70 @@ constructor( private val projectScoreName: String?, private val scoreType: ScoreType?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Project id */ fun projectId(): String? = projectId + /** Name of the project to search for */ fun projectName(): String? = projectName + /** Name of the project_score to search for */ fun projectScoreName(): String? = projectScoreName + /** The type of the configured score */ fun scoreType(): ScoreType? = scoreType + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.projectId?.let { params.put("project_id", listOf(it.toString())) } - this.projectName?.let { params.put("project_name", listOf(it.toString())) } - this.projectScoreName?.let { params.put("project_score_name", listOf(it.toString())) } - this.scoreType?.let { params.put("score_type", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectScoreListParams && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.projectId == other.projectId && - this.projectName == other.projectName && - this.projectScoreName == other.projectScoreName && - this.scoreType == other.scoreType && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - ids, - limit, - orgName, - projectId, - projectName, - projectScoreName, - scoreType, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "ProjectScoreListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, projectScoreName=$projectScoreName, scoreType=$scoreType, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ProjectScoreListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectScoreListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ProjectScoreListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var ids: Ids? = null @@ -130,21 +98,21 @@ constructor( private var projectScoreName: String? = null private var scoreType: ScoreType? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(projectScoreListParams: ProjectScoreListParams) = apply { - this.endingBefore = projectScoreListParams.endingBefore - this.ids = projectScoreListParams.ids - this.limit = projectScoreListParams.limit - this.orgName = projectScoreListParams.orgName - this.projectId = projectScoreListParams.projectId - this.projectName = projectScoreListParams.projectName - this.projectScoreName = projectScoreListParams.projectScoreName - this.scoreType = projectScoreListParams.scoreType - this.startingAfter = projectScoreListParams.startingAfter - additionalQueryParams(projectScoreListParams.additionalQueryParams) - additionalHeaders(projectScoreListParams.additionalHeaders) + endingBefore = projectScoreListParams.endingBefore + ids = projectScoreListParams.ids + limit = projectScoreListParams.limit + orgName = projectScoreListParams.orgName + projectId = projectScoreListParams.projectId + projectName = projectScoreListParams.projectName + projectScoreName = projectScoreListParams.projectScoreName + scoreType = projectScoreListParams.scoreType + startingAfter = projectScoreListParams.startingAfter + additionalHeaders = projectScoreListParams.additionalHeaders.toBuilder() + additionalQueryParams = projectScoreListParams.additionalQueryParams.toBuilder() } /** @@ -154,55 +122,55 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String?) = apply { this.projectId = projectId } /** Name of the project to search for */ - fun projectName(projectName: String) = apply { this.projectName = projectName } + fun projectName(projectName: String?) = apply { this.projectName = projectName } /** Name of the project_score to search for */ - fun projectScoreName(projectScoreName: String) = apply { + fun projectScoreName(projectScoreName: String?) = apply { this.projectScoreName = projectScoreName } /** The type of the configured score */ - fun scoreType(scoreType: ScoreType) = apply { this.scoreType = scoreType } + fun scoreType(scoreType: ScoreType?) = apply { this.scoreType = scoreType } - /** The type of the configured score */ - fun scoreType(projectScoreType: ProjectScoreType) = apply { - this.scoreType = ScoreType.ofProjectScoreType(projectScoreType) - } + /** Alias for calling [scoreType] with `ScoreType.ofProject(project)`. */ + fun scoreType(project: ProjectScoreType) = scoreType(ScoreType.ofProject(project)) - /** The type of the configured score */ - fun scoreType(projectScoreTypes: List) = apply { - this.scoreType = ScoreType.ofProjectScoreTypes(projectScoreTypes) - } + /** + * Alias for calling [scoreType] with `ScoreType.ofProjectScoreTypes(projectScoreTypes)`. + */ + fun scoreTypeOfProjectScoreTypes(projectScoreTypes: List) = + scoreType(ScoreType.ofProjectScoreTypes(projectScoreTypes)) /** * Pagination cursor id. @@ -211,48 +179,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ProjectScoreListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectScoreListParams = ProjectScoreListParams( endingBefore, @@ -264,22 +295,61 @@ constructor( projectScoreName, scoreType, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + projectId?.let { put("project_id", it) } + projectName?.let { put("project_name", it) } + projectScoreName?.let { put("project_score_name", it) } + scoreType?.accept( + object : ScoreType.Visitor { + override fun visitProject(project: ProjectScoreType) { + put("score_type", project.toString()) + } + + override fun visitProjectScoreTypes( + projectScoreTypes: List + ) { + put("score_type", projectScoreTypes.joinToString(",") { it.toString() }) + } + } + ) + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -292,139 +362,76 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) + else -> throw IllegalStateException("Invalid Ids") } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true - } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } - } - - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } - } - - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } } } - @JsonDeserialize(using = ScoreType.Deserializer::class) - @JsonSerialize(using = ScoreType.Serializer::class) + /** The type of the configured score */ class ScoreType private constructor( - private val projectScoreType: ProjectScoreType? = null, + private val project: ProjectScoreType? = null, private val projectScoreTypes: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - /** The type of the configured score */ - fun projectScoreType(): ProjectScoreType? = projectScoreType + fun project(): ProjectScoreType? = project + /** The type of the configured score */ fun projectScoreTypes(): List? = projectScoreTypes - fun isProjectScoreType(): Boolean = projectScoreType != null + fun isProject(): Boolean = project != null fun isProjectScoreTypes(): Boolean = projectScoreTypes != null - fun asProjectScoreType(): ProjectScoreType = projectScoreType.getOrThrow("projectScoreType") + /** The type of the configured score */ + fun asProject(): ProjectScoreType = project.getOrThrow("project") + /** The type of the configured score */ fun asProjectScoreTypes(): List = projectScoreTypes.getOrThrow("projectScoreTypes") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { - projectScoreType != null -> visitor.visitProjectScoreType(projectScoreType) + fun accept(visitor: Visitor): T = + when { + project != null -> visitor.visitProject(project) projectScoreTypes != null -> visitor.visitProjectScoreTypes(projectScoreTypes) - else -> visitor.unknown(_json) - } - } - - fun validate(): ScoreType = apply { - if (!validated) { - if (projectScoreType == null && projectScoreTypes == null) { - throw BraintrustInvalidDataException("Unknown ScoreType: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid ScoreType") } - } override fun equals(other: Any?): Boolean { if (this === other) { @@ -432,73 +439,76 @@ constructor( } return other is ScoreType && - this.projectScoreType == other.projectScoreType && - this.projectScoreTypes == other.projectScoreTypes + project == other.project && + projectScoreTypes == other.projectScoreTypes } - override fun hashCode(): Int { - return Objects.hash(projectScoreType, projectScoreTypes) - } + override fun hashCode(): Int = Objects.hash(project, projectScoreTypes) - override fun toString(): String { - return when { - projectScoreType != null -> "ScoreType{projectScoreType=$projectScoreType}" + override fun toString(): String = + when { + project != null -> "ScoreType{project=$project}" projectScoreTypes != null -> "ScoreType{projectScoreTypes=$projectScoreTypes}" - _json != null -> "ScoreType{_unknown=$_json}" else -> throw IllegalStateException("Invalid ScoreType") } - } companion object { - fun ofProjectScoreType(projectScoreType: ProjectScoreType) = - ScoreType(projectScoreType = projectScoreType) + /** The type of the configured score */ + fun ofProject(project: ProjectScoreType) = ScoreType(project = project) + /** The type of the configured score */ fun ofProjectScoreTypes(projectScoreTypes: List) = - ScoreType(projectScoreTypes = projectScoreTypes) + ScoreType(projectScoreTypes = projectScoreTypes.toImmutable()) } + /** + * An interface that defines how to map each variant of [ScoreType] to a value of type [T]. + */ interface Visitor { - fun visitProjectScoreType(projectScoreType: ProjectScoreType): T + /** The type of the configured score */ + fun visitProject(project: ProjectScoreType): T + /** The type of the configured score */ fun visitProjectScoreTypes(projectScoreTypes: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown ScoreType: $json") - } } + } - class Deserializer : BaseDeserializer(ScoreType::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): ScoreType { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return ScoreType(projectScoreType = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return ScoreType(projectScoreTypes = it, _json = json) - } - - return ScoreType(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(ScoreType::class) { - - override fun serialize( - value: ScoreType, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.projectScoreType != null -> generator.writeObject(value.projectScoreType) - value.projectScoreTypes != null -> - generator.writeObject(value.projectScoreTypes) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid ScoreType") - } - } - } + return other is ProjectScoreListParams && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + projectId == other.projectId && + projectName == other.projectName && + projectScoreName == other.projectScoreName && + scoreType == other.scoreType && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + ids, + limit, + orgName, + projectId, + projectName, + projectScoreName, + scoreType, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ProjectScoreListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, projectScoreName=$projectScoreName, scoreType=$scoreType, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParams.kt index 259bba6c..09c27994 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParams.kt @@ -5,13 +5,20 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.BaseDeserializer import com.braintrustdata.api.core.BaseSerializer import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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 @@ -20,540 +27,972 @@ 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 +/** + * Create or replace project_score. If there is an existing project_score in the project with the + * same name as the one specified in the request, will replace the existing project_score with the + * provided fields + */ class ProjectScoreReplaceParams -constructor( - private val name: String, - private val projectId: String, - private val scoreType: ProjectScoreType, - private val categories: Categories?, - private val config: ProjectScoreConfig?, - private val description: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun projectId(): String = projectId - - fun scoreType(): ProjectScoreType = scoreType - - fun categories(): Categories? = categories - - fun config(): ProjectScoreConfig? = config - - fun description(): String? = description - - internal fun getBody(): ProjectScoreReplaceBody { - return ProjectScoreReplaceBody( - name, - projectId, - scoreType, - categories, - config, - description, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the project score + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the project score belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * The type of the configured score + * + * @throws BraintrustInvalidDataException 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 scoreType(): ProjectScoreType = body.scoreType() + + /** + * For categorical-type project scores, the list of all categories + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun categories(): Categories? = body.categories() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun config(): ProjectScoreConfig? = body.config() + + /** + * Textual description of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [scoreType]. + * + * Unlike [scoreType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _scoreType(): JsonField = body._scoreType() + + /** + * Returns the raw JSON value of [categories]. + * + * Unlike [categories], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _categories(): JsonField = body._categories() + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _config(): JsonField = body._config() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + 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 [ProjectScoreReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectScoreReplaceParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - /** A project score is a user-configured score, which can be manually-labeled through the UI */ - @JsonDeserialize(builder = ProjectScoreReplaceBody.Builder::class) - @NoAutoDetect - class ProjectScoreReplaceBody - internal constructor( - private val name: String?, - private val projectId: String?, - private val scoreType: ProjectScoreType?, - private val categories: Categories?, - private val config: ProjectScoreConfig?, - private val description: String?, - private val additionalProperties: Map, - ) { + internal fun from(projectScoreReplaceParams: ProjectScoreReplaceParams) = apply { + body = projectScoreReplaceParams.body.toBuilder() + additionalHeaders = projectScoreReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = projectScoreReplaceParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [projectId] + * - [scoreType] + * - [categories] + * - [config] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the project score */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the project score belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** The type of the configured score */ - @JsonProperty("score_type") fun scoreType(): ProjectScoreType? = scoreType + fun scoreType(scoreType: ProjectScoreType) = apply { body.scoreType(scoreType) } + + /** + * Sets [Builder.scoreType] to an arbitrary JSON value. + * + * You should usually call [Builder.scoreType] with a well-typed [ProjectScoreType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun scoreType(scoreType: JsonField) = apply { body.scoreType(scoreType) } + + /** For categorical-type project scores, the list of all categories */ + fun categories(categories: Categories?) = apply { body.categories(categories) } + + /** + * Sets [Builder.categories] to an arbitrary JSON value. + * + * You should usually call [Builder.categories] with a well-typed [Categories] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun categories(categories: JsonField) = apply { body.categories(categories) } + + /** Alias for calling [categories] with `Categories.ofCategorical(categorical)`. */ + fun categoriesOfCategorical(categorical: List) = apply { + body.categoriesOfCategorical(categorical) + } + + /** Alias for calling [categories] with `Categories.ofWeighted(weighted)`. */ + fun categories(weighted: Categories.Weighted) = apply { body.categories(weighted) } + + /** Alias for calling [categories] with `Categories.ofMinimum(minimum)`. */ + fun categoriesOfMinimum(minimum: List) = apply { body.categoriesOfMinimum(minimum) } - @JsonProperty("categories") fun categories(): Categories? = categories + fun config(config: ProjectScoreConfig?) = apply { body.config(config) } - @JsonProperty("config") fun config(): ProjectScoreConfig? = config + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [ProjectScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun config(config: JsonField) = apply { body.config(config) } /** Textual description of the project score */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(description) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * 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 { body.description(description) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is ProjectScoreReplaceBody && - this.name == other.name && - this.projectId == other.projectId && - this.scoreType == other.scoreType && - this.categories == other.categories && - this.config == other.config && - this.description == other.description && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - projectId, - scoreType, - categories, - config, - description, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "ProjectScoreReplaceBody{name=$name, projectId=$projectId, scoreType=$scoreType, categories=$categories, config=$config, description=$description, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var projectId: String? = null - private var scoreType: ProjectScoreType? = null - private var categories: Categories? = null - private var config: ProjectScoreConfig? = null - private var description: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectScoreReplaceBody: ProjectScoreReplaceBody) = apply { - this.name = projectScoreReplaceBody.name - this.projectId = projectScoreReplaceBody.projectId - this.scoreType = projectScoreReplaceBody.scoreType - this.categories = projectScoreReplaceBody.categories - this.config = projectScoreReplaceBody.config - this.description = projectScoreReplaceBody.description - additionalProperties(projectScoreReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the project score */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Unique identifier for the project that the project score belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The type of the configured score */ - @JsonProperty("score_type") - fun scoreType(scoreType: ProjectScoreType) = apply { this.scoreType = scoreType } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("categories") - fun categories(categories: Categories) = apply { this.categories = categories } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("config") - fun config(config: ProjectScoreConfig) = apply { this.config = config } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** Textual description of the project score */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): ProjectScoreReplaceBody = - ProjectScoreReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(scoreType) { "`scoreType` is required but was not set" }, - categories, - config, - description, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ProjectScoreReplaceParams && - this.name == other.name && - this.projectId == other.projectId && - this.scoreType == other.scoreType && - this.categories == other.categories && - this.config == other.config && - this.description == other.description && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ProjectScoreReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectScoreReplaceParams = + ProjectScoreReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - projectId, - scoreType, - categories, - config, - description, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "ProjectScoreReplaceParams{name=$name, projectId=$projectId, scoreType=$scoreType, categories=$categories, config=$config, description=$description, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + /** A project score is a user-configured score, which can be manually-labeled through the UI */ + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val projectId: JsonField, + private val scoreType: JsonField, + private val categories: JsonField, + private val config: JsonField, + private val description: JsonField, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("score_type") + @ExcludeMissing + scoreType: JsonField = JsonMissing.of(), + @JsonProperty("categories") + @ExcludeMissing + categories: JsonField = JsonMissing.of(), + @JsonProperty("config") + @ExcludeMissing + config: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + ) : this(name, projectId, scoreType, categories, config, description, mutableMapOf()) + + /** + * Name of the project score + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the project score belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * The type of the configured score + * + * @throws BraintrustInvalidDataException 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 scoreType(): ProjectScoreType = scoreType.getRequired("score_type") + + /** + * For categorical-type project scores, the list of all categories + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun categories(): Categories? = categories.getNullable("categories") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun config(): ProjectScoreConfig? = config.getNullable("config") + + /** + * Textual description of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [scoreType]. + * + * Unlike [scoreType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("score_type") + @ExcludeMissing + fun _scoreType(): JsonField = scoreType + + /** + * Returns the raw JSON value of [categories]. + * + * Unlike [categories], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("categories") + @ExcludeMissing + fun _categories(): JsonField = categories + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("config") + @ExcludeMissing + fun _config(): JsonField = config + + /** + * 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 + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @NoAutoDetect - class Builder { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var name: String? = null - private var projectId: String? = null - private var scoreType: ProjectScoreType? = null - private var categories: Categories? = null - private var config: ProjectScoreConfig? = null - private var description: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(projectScoreReplaceParams: ProjectScoreReplaceParams) = apply { - this.name = projectScoreReplaceParams.name - this.projectId = projectScoreReplaceParams.projectId - this.scoreType = projectScoreReplaceParams.scoreType - this.categories = projectScoreReplaceParams.categories - this.config = projectScoreReplaceParams.config - this.description = projectScoreReplaceParams.description - additionalQueryParams(projectScoreReplaceParams.additionalQueryParams) - additionalHeaders(projectScoreReplaceParams.additionalHeaders) - additionalBodyProperties(projectScoreReplaceParams.additionalBodyProperties) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + */ + fun builder() = Builder() } - /** Name of the project score */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Unique identifier for the project that the project score belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var name: JsonField? = null + private var projectId: JsonField? = null + private var scoreType: JsonField? = null + private var categories: JsonField = JsonMissing.of() + private var config: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** The type of the configured score */ - fun scoreType(scoreType: ProjectScoreType) = apply { this.scoreType = scoreType } + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + scoreType = body.scoreType + categories = body.categories + config = body.config + description = body.description + additionalProperties = body.additionalProperties.toMutableMap() + } - /** For categorical-type project scores, the list of all categories */ - fun categories(categories: Categories) = apply { this.categories = categories } + /** Name of the project score */ + fun name(name: String) = name(JsonField.of(name)) - /** For categorical-type project scores, the list of all categories */ - fun projectScoreCategories(projectScoreCategories: List) = apply { - this.categories = Categories.ofProjectScoreCategories(projectScoreCategories) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** For categorical-type project scores, the list of all categories */ - fun categories(weighted: Categories.Weighted) = apply { - this.categories = Categories.ofWeighted(weighted) - } + /** Unique identifier for the project that the project score belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** For categorical-type project scores, the list of all categories */ - fun categories(strings: List) = apply { - this.categories = Categories.ofStrings(strings) - } + /** + * 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 } - /** For categorical-type project scores, the list of all categories */ - fun categories(nullableVariant: Categories.NullableVariant) = apply { - this.categories = Categories.ofNullableVariant(nullableVariant) - } + /** The type of the configured score */ + fun scoreType(scoreType: ProjectScoreType) = scoreType(JsonField.of(scoreType)) + + /** + * Sets [Builder.scoreType] to an arbitrary JSON value. + * + * You should usually call [Builder.scoreType] with a well-typed [ProjectScoreType] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun scoreType(scoreType: JsonField) = apply { + this.scoreType = scoreType + } - fun config(config: ProjectScoreConfig) = apply { this.config = config } + /** For categorical-type project scores, the list of all categories */ + fun categories(categories: Categories?) = categories(JsonField.ofNullable(categories)) + + /** + * Sets [Builder.categories] to an arbitrary JSON value. + * + * You should usually call [Builder.categories] with a well-typed [Categories] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun categories(categories: JsonField) = apply { + this.categories = categories + } - /** Textual description of the project score */ - fun description(description: String) = apply { this.description = description } + /** Alias for calling [categories] with `Categories.ofCategorical(categorical)`. */ + fun categoriesOfCategorical(categorical: List) = + categories(Categories.ofCategorical(categorical)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** Alias for calling [categories] with `Categories.ofWeighted(weighted)`. */ + fun categories(weighted: Categories.Weighted) = + categories(Categories.ofWeighted(weighted)) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Alias for calling [categories] with `Categories.ofMinimum(minimum)`. */ + fun categoriesOfMinimum(minimum: List) = + categories(Categories.ofMinimum(minimum)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun config(config: ProjectScoreConfig?) = config(JsonField.ofNullable(config)) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [ProjectScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun config(config: JsonField) = apply { this.config = config } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** Textual description of the project score */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .scoreType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("scoreType", scoreType), + categories, + config, + description, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + projectId() + scoreType().validate() + categories()?.validate() + config()?.validate() + description() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ProjectScoreReplaceParams = - ProjectScoreReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(scoreType) { "`scoreType` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (scoreType.asKnown()?.validity() ?: 0) + + (categories.asKnown()?.validity() ?: 0) + + (config.asKnown()?.validity() ?: 0) + + (if (description.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + projectId == other.projectId && + scoreType == other.scoreType && + categories == other.categories && + config == other.config && + description == other.description && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + name, + projectId, + scoreType, categories, config, description, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, projectId=$projectId, scoreType=$scoreType, categories=$categories, config=$config, description=$description, additionalProperties=$additionalProperties}" } + /** For categorical-type project scores, the list of all categories */ @JsonDeserialize(using = Categories.Deserializer::class) @JsonSerialize(using = Categories.Serializer::class) class Categories private constructor( - private val projectScoreCategories: List? = null, + private val categorical: List? = null, private val weighted: Weighted? = null, - private val strings: List? = null, - private val nullableVariant: NullableVariant? = null, + private val minimum: List? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - /** For categorical-type project scores, the list of all categories */ - fun projectScoreCategories(): List? = projectScoreCategories + fun categorical(): List? = categorical + /** For weighted-type project scores, the weights of each score */ fun weighted(): Weighted? = weighted - /** For minimum-type project scores, the list of included scores */ - fun strings(): List? = strings - fun nullableVariant(): NullableVariant? = nullableVariant + /** For minimum-type project scores, the list of included scores */ + fun minimum(): List? = minimum - fun isProjectScoreCategories(): Boolean = projectScoreCategories != null + fun isCategorical(): Boolean = categorical != null fun isWeighted(): Boolean = weighted != null - fun isStrings(): Boolean = strings != null - - fun isNullableVariant(): Boolean = nullableVariant != null + fun isMinimum(): Boolean = minimum != null - fun asProjectScoreCategories(): List = - projectScoreCategories.getOrThrow("projectScoreCategories") + /** For categorical-type project scores, the list of all categories */ + fun asCategorical(): List = categorical.getOrThrow("categorical") + /** For weighted-type project scores, the weights of each score */ fun asWeighted(): Weighted = weighted.getOrThrow("weighted") - fun asStrings(): List = strings.getOrThrow("strings") - - fun asNullableVariant(): NullableVariant = nullableVariant.getOrThrow("nullableVariant") + /** For minimum-type project scores, the list of included scores */ + fun asMinimum(): List = minimum.getOrThrow("minimum") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - projectScoreCategories != null -> - visitor.visitProjectScoreCategories(projectScoreCategories) + fun accept(visitor: Visitor): T = + when { + categorical != null -> visitor.visitCategorical(categorical) weighted != null -> visitor.visitWeighted(weighted) - strings != null -> visitor.visitStrings(strings) - nullableVariant != null -> visitor.visitNullableVariant(nullableVariant) + minimum != null -> visitor.visitMinimum(minimum) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Categories = apply { - if (!validated) { - if ( - projectScoreCategories == null && - weighted == null && - strings == null && - nullableVariant == null - ) { - throw BraintrustInvalidDataException("Unknown Categories: $_json") - } - projectScoreCategories?.forEach { it.validate() } - weighted?.validate() - nullableVariant?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitCategorical(categorical: List) { + categorical.forEach { it.validate() } + } + + override fun visitWeighted(weighted: Weighted) { + weighted.validate() + } + + override fun visitMinimum(minimum: List) {} + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitCategorical(categorical: List) = + categorical.sumOf { it.validity().toInt() } + + override fun visitWeighted(weighted: Weighted) = weighted.validity() + + override fun visitMinimum(minimum: List) = minimum.size + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is Categories && - this.projectScoreCategories == other.projectScoreCategories && - this.weighted == other.weighted && - this.strings == other.strings && - this.nullableVariant == other.nullableVariant - } - - override fun hashCode(): Int { - return Objects.hash( - projectScoreCategories, - weighted, - strings, - nullableVariant, - ) + categorical == other.categorical && + weighted == other.weighted && + minimum == other.minimum } - override fun toString(): String { - return when { - projectScoreCategories != null -> - "Categories{projectScoreCategories=$projectScoreCategories}" + override fun hashCode(): Int = Objects.hash(categorical, weighted, minimum) + + override fun toString(): String = + when { + categorical != null -> "Categories{categorical=$categorical}" weighted != null -> "Categories{weighted=$weighted}" - strings != null -> "Categories{strings=$strings}" - nullableVariant != null -> "Categories{nullableVariant=$nullableVariant}" + minimum != null -> "Categories{minimum=$minimum}" _json != null -> "Categories{_unknown=$_json}" else -> throw IllegalStateException("Invalid Categories") } - } companion object { - fun ofProjectScoreCategories(projectScoreCategories: List) = - Categories(projectScoreCategories = projectScoreCategories) + /** For categorical-type project scores, the list of all categories */ + fun ofCategorical(categorical: List) = + Categories(categorical = categorical.toImmutable()) + /** For weighted-type project scores, the weights of each score */ fun ofWeighted(weighted: Weighted) = Categories(weighted = weighted) - fun ofStrings(strings: List) = Categories(strings = strings) - - fun ofNullableVariant(nullableVariant: NullableVariant) = - Categories(nullableVariant = nullableVariant) + /** For minimum-type project scores, the list of included scores */ + fun ofMinimum(minimum: List) = Categories(minimum = minimum.toImmutable()) } + /** + * An interface that defines how to map each variant of [Categories] to a value of type [T]. + */ interface Visitor { - fun visitProjectScoreCategories(projectScoreCategories: List): T + /** For categorical-type project scores, the list of all categories */ + fun visitCategorical(categorical: List): T + /** For weighted-type project scores, the weights of each score */ fun visitWeighted(weighted: Weighted): T - fun visitStrings(strings: List): T - - fun visitNullableVariant(nullableVariant: NullableVariant): T - + /** For minimum-type project scores, the list of included scores */ + fun visitMinimum(minimum: List): T + + /** + * Maps an unknown variant of [Categories] to a value of type [T]. + * + * An instance of [Categories] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Categories: $json") } } - class Deserializer : BaseDeserializer(Categories::class) { + internal class Deserializer : BaseDeserializer(Categories::class) { override fun ObjectCodec.deserialize(node: JsonNode): Categories { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef>()) { - it.forEach { it.validate() } - } - ?.let { - return Categories(projectScoreCategories = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(weighted = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Categories(strings = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(nullableVariant = it, _json = json) - } - return Categories(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Categories(weighted = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>()) + ?.let { Categories(categorical = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef>())?.let { + Categories(minimum = 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 -> Categories(_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() + } } } - class Serializer : BaseSerializer(Categories::class) { + internal class Serializer : BaseSerializer(Categories::class) { override fun serialize( value: Categories, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.projectScoreCategories != null -> - generator.writeObject(value.projectScoreCategories) + value.categorical != null -> generator.writeObject(value.categorical) value.weighted != null -> generator.writeObject(value.weighted) - value.strings != null -> generator.writeObject(value.strings) - value.nullableVariant != null -> generator.writeObject(value.nullableVariant) + value.minimum != null -> generator.writeObject(value.minimum) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Categories") } @@ -561,67 +1000,41 @@ constructor( } /** For weighted-type project scores, the weights of each score */ - @JsonDeserialize(builder = Weighted.Builder::class) - @NoAutoDetect class Weighted + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Weighted = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Weighted && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Weighted{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Weighted]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Weighted]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(weighted: Weighted) = apply { - additionalProperties(weighted.additionalProperties) + additionalProperties = weighted.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -629,82 +1042,78 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Weighted = Weighted(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - @JsonDeserialize(builder = NullableVariant.Builder::class) - @NoAutoDetect - class NullableVariant - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Weighted]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Weighted = Weighted(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Weighted = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): NullableVariant = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 NullableVariant && - this.additionalProperties == other.additionalProperties + return other is Weighted && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "NullableVariant{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(nullableVariant: NullableVariant) = apply { - additionalProperties(nullableVariant.additionalProperties) - } + override fun toString() = "Weighted{additionalProperties=$additionalProperties}" + } + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + return other is ProjectScoreReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun build(): NullableVariant = - NullableVariant(additionalProperties.toUnmodifiable()) - } - } - } + override fun toString() = + "ProjectScoreReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParams.kt index 1394924c..71d20316 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParams.kt @@ -2,125 +2,191 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a project_score object by its id */ class ProjectScoreRetrieveParams -constructor( - private val projectScoreId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val projectScoreId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun projectScoreId(): String = projectScoreId + /** ProjectScore id */ + fun projectScoreId(): String? = projectScoreId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectScoreId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ProjectScoreRetrieveParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [ProjectScoreRetrieveParams]. + */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectScoreRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var projectScoreId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(projectScoreRetrieveParams: ProjectScoreRetrieveParams) = apply { + projectScoreId = projectScoreRetrieveParams.projectScoreId + additionalHeaders = projectScoreRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = projectScoreRetrieveParams.additionalQueryParams.toBuilder() } - return other is ProjectScoreRetrieveParams && - this.projectScoreId == other.projectScoreId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** ProjectScore id */ + fun projectScoreId(projectScoreId: String?) = apply { this.projectScoreId = projectScoreId } - override fun hashCode(): Int { - return Objects.hash( - projectScoreId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "ProjectScoreRetrieveParams{projectScoreId=$projectScoreId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var projectScoreId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(projectScoreRetrieveParams: ProjectScoreRetrieveParams) = apply { - this.projectScoreId = projectScoreRetrieveParams.projectScoreId - additionalQueryParams(projectScoreRetrieveParams.additionalQueryParams) - additionalHeaders(projectScoreRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** ProjectScore id */ - fun projectScoreId(projectScoreId: String) = apply { this.projectScoreId = projectScoreId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ProjectScoreRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectScoreRetrieveParams = ProjectScoreRetrieveParams( - checkNotNull(projectScoreId) { "`projectScoreId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + projectScoreId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectScoreId ?: "" + 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 ProjectScoreRetrieveParams && + projectScoreId == other.projectScoreId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(projectScoreId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectScoreRetrieveParams{projectScoreId=$projectScoreId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreType.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreType.kt index f56f006a..dafbc8a7 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreType.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreType.kt @@ -4,81 +4,162 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonValue import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.fasterxml.jackson.annotation.JsonCreator -class ProjectScoreType -@JsonCreator -private constructor( - private val value: JsonField, -) : Enum { - +/** The type of the configured score */ +class ProjectScoreType @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 - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectScoreType && this.value == other.value - } - - override fun hashCode() = value.hashCode() + companion object { - override fun toString() = value.toString() + val SLIDER = of("slider") - companion object { + val CATEGORICAL = of("categorical") - val SLIDER = ProjectScoreType(JsonField.of("slider")) + val WEIGHTED = of("weighted") - val CATEGORICAL = ProjectScoreType(JsonField.of("categorical")) + val MINIMUM = of("minimum") - val WEIGHTED = ProjectScoreType(JsonField.of("weighted")) + val MAXIMUM = of("maximum") - val MINIMUM = ProjectScoreType(JsonField.of("minimum")) + val ONLINE = of("online") - val ONLINE = ProjectScoreType(JsonField.of("online")) + val FREE_FORM = of("free-form") fun of(value: String) = ProjectScoreType(JsonField.of(value)) } + /** An enum containing [ProjectScoreType]'s known values. */ enum class Known { SLIDER, CATEGORICAL, WEIGHTED, MINIMUM, + MAXIMUM, ONLINE, + FREE_FORM, } + /** + * An enum containing [ProjectScoreType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ProjectScoreType] 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 { SLIDER, CATEGORICAL, WEIGHTED, MINIMUM, + MAXIMUM, ONLINE, + FREE_FORM, + /** + * An enum member indicating that [ProjectScoreType] 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) { SLIDER -> Value.SLIDER CATEGORICAL -> Value.CATEGORICAL WEIGHTED -> Value.WEIGHTED MINIMUM -> Value.MINIMUM + MAXIMUM -> Value.MAXIMUM ONLINE -> Value.ONLINE + FREE_FORM -> Value.FREE_FORM 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { SLIDER -> Known.SLIDER CATEGORICAL -> Known.CATEGORICAL WEIGHTED -> Known.WEIGHTED MINIMUM -> Known.MINIMUM + MAXIMUM -> Known.MAXIMUM ONLINE -> Known.ONLINE + FREE_FORM -> Known.FREE_FORM else -> throw BraintrustInvalidDataException("Unknown ProjectScoreType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ProjectScoreType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + 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 ProjectScoreType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParams.kt index 5cfe9ff9..891a9332 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParams.kt @@ -5,13 +5,19 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.BaseDeserializer import com.braintrustdata.api.core.BaseSerializer import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.allMaxBy import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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 @@ -20,533 +26,882 @@ 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 +/** + * Partially update a project_score object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ class ProjectScoreUpdateParams -constructor( - private val projectScoreId: String, - private val categories: Categories?, - private val config: ProjectScoreConfig?, - private val description: String?, - private val name: String?, - private val scoreType: ProjectScoreType?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun projectScoreId(): String = projectScoreId - - fun categories(): Categories? = categories - - fun config(): ProjectScoreConfig? = config - - fun description(): String? = description - - fun name(): String? = name - - fun scoreType(): ProjectScoreType? = scoreType - - internal fun getBody(): ProjectScoreUpdateBody { - return ProjectScoreUpdateBody( - categories, - config, - description, - name, - scoreType, - additionalBodyProperties, - ) +private constructor( + private val projectScoreId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** ProjectScore id */ + fun projectScoreId(): String? = projectScoreId + + /** + * For categorical-type project scores, the list of all categories + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun categories(): Categories? = body.categories() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun config(): ProjectScoreConfig? = body.config() + + /** + * Textual description of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Name of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * The type of the configured score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun scoreType(): ProjectScoreType? = body.scoreType() + + /** + * Returns the raw JSON value of [categories]. + * + * Unlike [categories], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _categories(): JsonField = body._categories() + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _config(): JsonField = body._config() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [scoreType]. + * + * Unlike [scoreType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _scoreType(): JsonField = body._scoreType() + + 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 { + + fun none(): ProjectScoreUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectScoreUpdateParams]. */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectScoreUpdateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var projectScoreId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectScoreId - else -> "" + internal fun from(projectScoreUpdateParams: ProjectScoreUpdateParams) = apply { + projectScoreId = projectScoreUpdateParams.projectScoreId + body = projectScoreUpdateParams.body.toBuilder() + additionalHeaders = projectScoreUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = projectScoreUpdateParams.additionalQueryParams.toBuilder() } - } - /** A project score is a user-configured score, which can be manually-labeled through the UI */ - @JsonDeserialize(builder = ProjectScoreUpdateBody.Builder::class) - @NoAutoDetect - class ProjectScoreUpdateBody - internal constructor( - private val categories: Categories?, - private val config: ProjectScoreConfig?, - private val description: String?, - private val name: String?, - private val scoreType: ProjectScoreType?, - private val additionalProperties: Map, - ) { + /** ProjectScore id */ + fun projectScoreId(projectScoreId: String?) = apply { this.projectScoreId = projectScoreId } + + /** + * 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: + * - [categories] + * - [config] + * - [description] + * - [name] + * - [scoreType] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** For categorical-type project scores, the list of all categories */ + fun categories(categories: Categories?) = apply { body.categories(categories) } + + /** + * Sets [Builder.categories] to an arbitrary JSON value. + * + * You should usually call [Builder.categories] with a well-typed [Categories] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun categories(categories: JsonField) = apply { body.categories(categories) } + + /** Alias for calling [categories] with `Categories.ofCategorical(categorical)`. */ + fun categoriesOfCategorical(categorical: List) = apply { + body.categoriesOfCategorical(categorical) + } + + /** Alias for calling [categories] with `Categories.ofWeighted(weighted)`. */ + fun categories(weighted: Categories.Weighted) = apply { body.categories(weighted) } - private var hashCode: Int = 0 + /** Alias for calling [categories] with `Categories.ofMinimum(minimum)`. */ + fun categoriesOfMinimum(minimum: List) = apply { body.categoriesOfMinimum(minimum) } - @JsonProperty("categories") fun categories(): Categories? = categories + fun config(config: ProjectScoreConfig?) = apply { body.config(config) } - @JsonProperty("config") fun config(): ProjectScoreConfig? = config + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [ProjectScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun config(config: JsonField) = apply { body.config(config) } /** Textual description of the project score */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** Name of the project score */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The type of the configured score */ - @JsonProperty("score_type") fun scoreType(): ProjectScoreType? = scoreType + fun scoreType(scoreType: ProjectScoreType?) = apply { body.scoreType(scoreType) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.scoreType] to an arbitrary JSON value. + * + * You should usually call [Builder.scoreType] with a well-typed [ProjectScoreType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun scoreType(scoreType: JsonField) = apply { body.scoreType(scoreType) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is ProjectScoreUpdateBody && - this.categories == other.categories && - this.config == other.config && - this.description == other.description && - this.name == other.name && - this.scoreType == other.scoreType && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - categories, - config, - description, - name, - scoreType, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "ProjectScoreUpdateBody{categories=$categories, config=$config, description=$description, name=$name, scoreType=$scoreType, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var categories: Categories? = null - private var config: ProjectScoreConfig? = null - private var description: String? = null - private var name: String? = null - private var scoreType: ProjectScoreType? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectScoreUpdateBody: ProjectScoreUpdateBody) = apply { - this.categories = projectScoreUpdateBody.categories - this.config = projectScoreUpdateBody.config - this.description = projectScoreUpdateBody.description - this.name = projectScoreUpdateBody.name - this.scoreType = projectScoreUpdateBody.scoreType - additionalProperties(projectScoreUpdateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @JsonProperty("categories") - fun categories(categories: Categories) = apply { this.categories = categories } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @JsonProperty("config") - fun config(config: ProjectScoreConfig) = apply { this.config = config } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Textual description of the project score */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Name of the project score */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The type of the configured score */ - @JsonProperty("score_type") - fun scoreType(scoreType: ProjectScoreType) = apply { this.scoreType = scoreType } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): ProjectScoreUpdateBody = - ProjectScoreUpdateBody( - categories, - config, - description, - name, - scoreType, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is ProjectScoreUpdateParams && - this.projectScoreId == other.projectScoreId && - this.categories == other.categories && - this.config == other.config && - this.description == other.description && - this.name == other.name && - this.scoreType == other.scoreType && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - projectScoreId, - categories, - config, - description, - name, - scoreType, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "ProjectScoreUpdateParams{projectScoreId=$projectScoreId, categories=$categories, config=$config, description=$description, name=$name, scoreType=$scoreType, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [ProjectScoreUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ProjectScoreUpdateParams = + ProjectScoreUpdateParams( + projectScoreId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { - - private var projectScoreId: String? = null - private var categories: Categories? = null - private var config: ProjectScoreConfig? = null - private var description: String? = null - private var name: String? = null - private var scoreType: ProjectScoreType? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun _body(): Body = body - internal fun from(projectScoreUpdateParams: ProjectScoreUpdateParams) = apply { - this.projectScoreId = projectScoreUpdateParams.projectScoreId - this.categories = projectScoreUpdateParams.categories - this.config = projectScoreUpdateParams.config - this.description = projectScoreUpdateParams.description - this.name = projectScoreUpdateParams.name - this.scoreType = projectScoreUpdateParams.scoreType - additionalQueryParams(projectScoreUpdateParams.additionalQueryParams) - additionalHeaders(projectScoreUpdateParams.additionalHeaders) - additionalBodyProperties(projectScoreUpdateParams.additionalBodyProperties) + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectScoreId ?: "" + else -> "" } - /** ProjectScore id */ - fun projectScoreId(projectScoreId: String) = apply { this.projectScoreId = projectScoreId } + override fun _headers(): Headers = additionalHeaders - /** For categorical-type project scores, the list of all categories */ - fun categories(categories: Categories) = apply { this.categories = categories } + override fun _queryParams(): QueryParams = additionalQueryParams - /** For categorical-type project scores, the list of all categories */ - fun projectScoreCategories(projectScoreCategories: List) = apply { - this.categories = Categories.ofProjectScoreCategories(projectScoreCategories) - } + /** A project score is a user-configured score, which can be manually-labeled through the UI */ + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val categories: JsonField, + private val config: JsonField, + private val description: JsonField, + private val name: JsonField, + private val scoreType: JsonField, + private val additionalProperties: MutableMap, + ) { - /** For categorical-type project scores, the list of all categories */ - fun categories(weighted: Categories.Weighted) = apply { - this.categories = Categories.ofWeighted(weighted) - } + @JsonCreator + private constructor( + @JsonProperty("categories") + @ExcludeMissing + categories: JsonField = JsonMissing.of(), + @JsonProperty("config") + @ExcludeMissing + config: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("score_type") + @ExcludeMissing + scoreType: JsonField = JsonMissing.of(), + ) : this(categories, config, description, name, scoreType, mutableMapOf()) + + /** + * For categorical-type project scores, the list of all categories + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun categories(): Categories? = categories.getNullable("categories") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun config(): ProjectScoreConfig? = config.getNullable("config") + + /** + * Textual description of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Name of the project score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * The type of the configured score + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun scoreType(): ProjectScoreType? = scoreType.getNullable("score_type") + + /** + * Returns the raw JSON value of [categories]. + * + * Unlike [categories], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("categories") + @ExcludeMissing + fun _categories(): JsonField = categories + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("config") + @ExcludeMissing + fun _config(): JsonField = config + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [scoreType]. + * + * Unlike [scoreType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("score_type") + @ExcludeMissing + fun _scoreType(): JsonField = scoreType - /** For categorical-type project scores, the list of all categories */ - fun categories(strings: List) = apply { - this.categories = Categories.ofStrings(strings) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - /** For categorical-type project scores, the list of all categories */ - fun categories(nullableVariant: Categories.NullableVariant) = apply { - this.categories = Categories.ofNullableVariant(nullableVariant) + @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]. */ + fun builder() = Builder() } - fun config(config: ProjectScoreConfig) = apply { this.config = config } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Textual description of the project score */ - fun description(description: String) = apply { this.description = description } + private var categories: JsonField = JsonMissing.of() + private var config: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var scoreType: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** Name of the project score */ - fun name(name: String) = apply { this.name = name } + internal fun from(body: Body) = apply { + categories = body.categories + config = body.config + description = body.description + name = body.name + scoreType = body.scoreType + additionalProperties = body.additionalProperties.toMutableMap() + } - /** The type of the configured score */ - fun scoreType(scoreType: ProjectScoreType) = apply { this.scoreType = scoreType } + /** For categorical-type project scores, the list of all categories */ + fun categories(categories: Categories?) = categories(JsonField.ofNullable(categories)) + + /** + * Sets [Builder.categories] to an arbitrary JSON value. + * + * You should usually call [Builder.categories] with a well-typed [Categories] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun categories(categories: JsonField) = apply { + this.categories = categories + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** Alias for calling [categories] with `Categories.ofCategorical(categorical)`. */ + fun categoriesOfCategorical(categorical: List) = + categories(Categories.ofCategorical(categorical)) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Alias for calling [categories] with `Categories.ofWeighted(weighted)`. */ + fun categories(weighted: Categories.Weighted) = + categories(Categories.ofWeighted(weighted)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** Alias for calling [categories] with `Categories.ofMinimum(minimum)`. */ + fun categoriesOfMinimum(minimum: List) = + categories(Categories.ofMinimum(minimum)) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + fun config(config: ProjectScoreConfig?) = config(JsonField.ofNullable(config)) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [ProjectScoreConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun config(config: JsonField) = apply { this.config = config } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** Textual description of the project score */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + /** Name of the project score */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** The type of the configured score */ + fun scoreType(scoreType: ProjectScoreType?) = scoreType(JsonField.ofNullable(scoreType)) + + /** + * Sets [Builder.scoreType] to an arbitrary JSON value. + * + * You should usually call [Builder.scoreType] with a well-typed [ProjectScoreType] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun scoreType(scoreType: JsonField) = apply { + this.scoreType = scoreType + } + + 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 putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + 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( + categories, + config, + description, + name, + scoreType, + additionalProperties.toMutableMap(), + ) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + categories()?.validate() + config()?.validate() + description() + name() + scoreType()?.validate() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (categories.asKnown()?.validity() ?: 0) + + (config.asKnown()?.validity() ?: 0) + + (if (description.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (scoreType.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + categories == other.categories && + config == other.config && + description == other.description && + name == other.name && + scoreType == other.scoreType && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(categories, config, description, name, scoreType, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): ProjectScoreUpdateParams = - ProjectScoreUpdateParams( - checkNotNull(projectScoreId) { "`projectScoreId` is required but was not set" }, - categories, - config, - description, - name, - scoreType, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{categories=$categories, config=$config, description=$description, name=$name, scoreType=$scoreType, additionalProperties=$additionalProperties}" } + /** For categorical-type project scores, the list of all categories */ @JsonDeserialize(using = Categories.Deserializer::class) @JsonSerialize(using = Categories.Serializer::class) class Categories private constructor( - private val projectScoreCategories: List? = null, + private val categorical: List? = null, private val weighted: Weighted? = null, - private val strings: List? = null, - private val nullableVariant: NullableVariant? = null, + private val minimum: List? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - /** For categorical-type project scores, the list of all categories */ - fun projectScoreCategories(): List? = projectScoreCategories + fun categorical(): List? = categorical + /** For weighted-type project scores, the weights of each score */ fun weighted(): Weighted? = weighted - /** For minimum-type project scores, the list of included scores */ - fun strings(): List? = strings - fun nullableVariant(): NullableVariant? = nullableVariant + /** For minimum-type project scores, the list of included scores */ + fun minimum(): List? = minimum - fun isProjectScoreCategories(): Boolean = projectScoreCategories != null + fun isCategorical(): Boolean = categorical != null fun isWeighted(): Boolean = weighted != null - fun isStrings(): Boolean = strings != null - - fun isNullableVariant(): Boolean = nullableVariant != null + fun isMinimum(): Boolean = minimum != null - fun asProjectScoreCategories(): List = - projectScoreCategories.getOrThrow("projectScoreCategories") + /** For categorical-type project scores, the list of all categories */ + fun asCategorical(): List = categorical.getOrThrow("categorical") + /** For weighted-type project scores, the weights of each score */ fun asWeighted(): Weighted = weighted.getOrThrow("weighted") - fun asStrings(): List = strings.getOrThrow("strings") - - fun asNullableVariant(): NullableVariant = nullableVariant.getOrThrow("nullableVariant") + /** For minimum-type project scores, the list of included scores */ + fun asMinimum(): List = minimum.getOrThrow("minimum") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - projectScoreCategories != null -> - visitor.visitProjectScoreCategories(projectScoreCategories) + fun accept(visitor: Visitor): T = + when { + categorical != null -> visitor.visitCategorical(categorical) weighted != null -> visitor.visitWeighted(weighted) - strings != null -> visitor.visitStrings(strings) - nullableVariant != null -> visitor.visitNullableVariant(nullableVariant) + minimum != null -> visitor.visitMinimum(minimum) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Categories = apply { - if (!validated) { - if ( - projectScoreCategories == null && - weighted == null && - strings == null && - nullableVariant == null - ) { - throw BraintrustInvalidDataException("Unknown Categories: $_json") - } - projectScoreCategories?.forEach { it.validate() } - weighted?.validate() - nullableVariant?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitCategorical(categorical: List) { + categorical.forEach { it.validate() } + } + + override fun visitWeighted(weighted: Weighted) { + weighted.validate() + } + + override fun visitMinimum(minimum: List) {} + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitCategorical(categorical: List) = + categorical.sumOf { it.validity().toInt() } + + override fun visitWeighted(weighted: Weighted) = weighted.validity() + + override fun visitMinimum(minimum: List) = minimum.size + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is Categories && - this.projectScoreCategories == other.projectScoreCategories && - this.weighted == other.weighted && - this.strings == other.strings && - this.nullableVariant == other.nullableVariant - } - - override fun hashCode(): Int { - return Objects.hash( - projectScoreCategories, - weighted, - strings, - nullableVariant, - ) + categorical == other.categorical && + weighted == other.weighted && + minimum == other.minimum } - override fun toString(): String { - return when { - projectScoreCategories != null -> - "Categories{projectScoreCategories=$projectScoreCategories}" + override fun hashCode(): Int = Objects.hash(categorical, weighted, minimum) + + override fun toString(): String = + when { + categorical != null -> "Categories{categorical=$categorical}" weighted != null -> "Categories{weighted=$weighted}" - strings != null -> "Categories{strings=$strings}" - nullableVariant != null -> "Categories{nullableVariant=$nullableVariant}" + minimum != null -> "Categories{minimum=$minimum}" _json != null -> "Categories{_unknown=$_json}" else -> throw IllegalStateException("Invalid Categories") } - } companion object { - fun ofProjectScoreCategories(projectScoreCategories: List) = - Categories(projectScoreCategories = projectScoreCategories) + /** For categorical-type project scores, the list of all categories */ + fun ofCategorical(categorical: List) = + Categories(categorical = categorical.toImmutable()) + /** For weighted-type project scores, the weights of each score */ fun ofWeighted(weighted: Weighted) = Categories(weighted = weighted) - fun ofStrings(strings: List) = Categories(strings = strings) - - fun ofNullableVariant(nullableVariant: NullableVariant) = - Categories(nullableVariant = nullableVariant) + /** For minimum-type project scores, the list of included scores */ + fun ofMinimum(minimum: List) = Categories(minimum = minimum.toImmutable()) } + /** + * An interface that defines how to map each variant of [Categories] to a value of type [T]. + */ interface Visitor { - fun visitProjectScoreCategories(projectScoreCategories: List): T + /** For categorical-type project scores, the list of all categories */ + fun visitCategorical(categorical: List): T + /** For weighted-type project scores, the weights of each score */ fun visitWeighted(weighted: Weighted): T - fun visitStrings(strings: List): T - - fun visitNullableVariant(nullableVariant: NullableVariant): T - + /** For minimum-type project scores, the list of included scores */ + fun visitMinimum(minimum: List): T + + /** + * Maps an unknown variant of [Categories] to a value of type [T]. + * + * An instance of [Categories] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Categories: $json") } } - class Deserializer : BaseDeserializer(Categories::class) { + internal class Deserializer : BaseDeserializer(Categories::class) { override fun ObjectCodec.deserialize(node: JsonNode): Categories { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef>()) { - it.forEach { it.validate() } - } - ?.let { - return Categories(projectScoreCategories = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(weighted = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Categories(strings = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Categories(nullableVariant = it, _json = json) - } - return Categories(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Categories(weighted = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>()) + ?.let { Categories(categorical = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef>())?.let { + Categories(minimum = 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 -> Categories(_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() + } } } - class Serializer : BaseSerializer(Categories::class) { + internal class Serializer : BaseSerializer(Categories::class) { override fun serialize( value: Categories, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.projectScoreCategories != null -> - generator.writeObject(value.projectScoreCategories) + value.categorical != null -> generator.writeObject(value.categorical) value.weighted != null -> generator.writeObject(value.weighted) - value.strings != null -> generator.writeObject(value.strings) - value.nullableVariant != null -> generator.writeObject(value.nullableVariant) + value.minimum != null -> generator.writeObject(value.minimum) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Categories") } @@ -554,67 +909,41 @@ constructor( } /** For weighted-type project scores, the weights of each score */ - @JsonDeserialize(builder = Weighted.Builder::class) - @NoAutoDetect class Weighted + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Weighted = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Weighted && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Weighted{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Weighted]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Weighted]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(weighted: Weighted) = apply { - additionalProperties(weighted.additionalProperties) + additionalProperties = weighted.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -622,82 +951,80 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Weighted = Weighted(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - @JsonDeserialize(builder = NullableVariant.Builder::class) - @NoAutoDetect - class NullableVariant - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Weighted]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Weighted = Weighted(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Weighted = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): NullableVariant = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 NullableVariant && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "NullableVariant{additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + return other is Weighted && additionalProperties == other.additionalProperties } - class Builder { + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - private var additionalProperties: MutableMap = mutableMapOf() + override fun hashCode(): Int = hashCode - internal fun from(nullableVariant: NullableVariant) = apply { - additionalProperties(nullableVariant.additionalProperties) - } + override fun toString() = "Weighted{additionalProperties=$additionalProperties}" + } + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + return other is ProjectScoreUpdateParams && + projectScoreId == other.projectScoreId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = + Objects.hash(projectScoreId, body, additionalHeaders, additionalQueryParams) - fun build(): NullableVariant = - NullableVariant(additionalProperties.toUnmodifiable()) - } - } - } + override fun toString() = + "ProjectScoreUpdateParams{projectScoreId=$projectScoreId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectSettings.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectSettings.kt index 6c5d7746..2a68c143 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectSettings.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectSettings.kt @@ -2,109 +2,661 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ProjectSettings.Builder::class) -@NoAutoDetect class ProjectSettings +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val baselineExperimentId: JsonField, private val comparisonKey: JsonField, - private val additionalProperties: Map, + private val spanFieldOrder: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("baseline_experiment_id") + @ExcludeMissing + baselineExperimentId: JsonField = JsonMissing.of(), + @JsonProperty("comparison_key") + @ExcludeMissing + comparisonKey: JsonField = JsonMissing.of(), + @JsonProperty("spanFieldOrder") + @ExcludeMissing + spanFieldOrder: JsonField> = JsonMissing.of(), + ) : this(baselineExperimentId, comparisonKey, spanFieldOrder, mutableMapOf()) - private var hashCode: Int = 0 + /** + * The id of the experiment to use as the default baseline for comparisons + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baselineExperimentId(): String? = baselineExperimentId.getNullable("baseline_experiment_id") - /** The key used to join two experiments (defaults to `input`). */ + /** + * The key used to join two experiments (defaults to `input`) + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun comparisonKey(): String? = comparisonKey.getNullable("comparison_key") - /** The key used to join two experiments (defaults to `input`). */ - @JsonProperty("comparison_key") @ExcludeMissing fun _comparisonKey() = comparisonKey + /** + * The order of the fields to display in the trace view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun spanFieldOrder(): List? = spanFieldOrder.getNullable("spanFieldOrder") - @JsonAnyGetter + /** + * Returns the raw JSON value of [baselineExperimentId]. + * + * Unlike [baselineExperimentId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("baseline_experiment_id") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ProjectSettings = apply { - if (!validated) { - comparisonKey() - validated = true - } - } + fun _baselineExperimentId(): JsonField = baselineExperimentId - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [comparisonKey]. + * + * Unlike [comparisonKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("comparison_key") + @ExcludeMissing + fun _comparisonKey(): JsonField = comparisonKey - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [spanFieldOrder]. + * + * Unlike [spanFieldOrder], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("spanFieldOrder") + @ExcludeMissing + fun _spanFieldOrder(): JsonField> = spanFieldOrder - return other is ProjectSettings && - this.comparisonKey == other.comparisonKey && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(comparisonKey, additionalProperties) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "ProjectSettings{comparisonKey=$comparisonKey, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [ProjectSettings]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ProjectSettings]. */ + class Builder internal constructor() { + private var baselineExperimentId: JsonField = JsonMissing.of() private var comparisonKey: JsonField = JsonMissing.of() + private var spanFieldOrder: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectSettings: ProjectSettings) = apply { - this.comparisonKey = projectSettings.comparisonKey - additionalProperties(projectSettings.additionalProperties) + baselineExperimentId = projectSettings.baselineExperimentId + comparisonKey = projectSettings.comparisonKey + spanFieldOrder = projectSettings.spanFieldOrder.map { it.toMutableList() } + additionalProperties = projectSettings.additionalProperties.toMutableMap() } - /** The key used to join two experiments (defaults to `input`). */ - fun comparisonKey(comparisonKey: String) = comparisonKey(JsonField.of(comparisonKey)) + /** The id of the experiment to use as the default baseline for comparisons */ + fun baselineExperimentId(baselineExperimentId: String?) = + baselineExperimentId(JsonField.ofNullable(baselineExperimentId)) - /** The key used to join two experiments (defaults to `input`). */ - @JsonProperty("comparison_key") - @ExcludeMissing + /** + * Sets [Builder.baselineExperimentId] to an arbitrary JSON value. + * + * You should usually call [Builder.baselineExperimentId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun baselineExperimentId(baselineExperimentId: JsonField) = apply { + this.baselineExperimentId = baselineExperimentId + } + + /** The key used to join two experiments (defaults to `input`) */ + fun comparisonKey(comparisonKey: String?) = + comparisonKey(JsonField.ofNullable(comparisonKey)) + + /** + * Sets [Builder.comparisonKey] to an arbitrary JSON value. + * + * You should usually call [Builder.comparisonKey] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun comparisonKey(comparisonKey: JsonField) = apply { this.comparisonKey = comparisonKey } + /** The order of the fields to display in the trace view */ + fun spanFieldOrder(spanFieldOrder: List?) = + spanFieldOrder(JsonField.ofNullable(spanFieldOrder)) + + /** + * Sets [Builder.spanFieldOrder] to an arbitrary JSON value. + * + * You should usually call [Builder.spanFieldOrder] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun spanFieldOrder(spanFieldOrder: JsonField>) = apply { + this.spanFieldOrder = spanFieldOrder.map { it.toMutableList() } + } + + /** + * Adds a single [SpanFieldOrder] to [Builder.spanFieldOrder]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSpanFieldOrder(spanFieldOrder: SpanFieldOrder) = apply { + this.spanFieldOrder = + (this.spanFieldOrder ?: JsonField.of(mutableListOf())).also { + checkKnown("spanFieldOrder", it).add(spanFieldOrder) + } + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ProjectSettings]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectSettings = - ProjectSettings(comparisonKey, additionalProperties.toUnmodifiable()) + ProjectSettings( + baselineExperimentId, + comparisonKey, + (spanFieldOrder ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } + + private var validated: Boolean = false + + fun validate(): ProjectSettings = apply { + if (validated) { + return@apply + } + + baselineExperimentId() + comparisonKey() + spanFieldOrder()?.forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (baselineExperimentId.asKnown() == null) 0 else 1) + + (if (comparisonKey.asKnown() == null) 0 else 1) + + (spanFieldOrder.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + class SpanFieldOrder + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val columnId: JsonField, + private val objectType: JsonField, + private val position: JsonField, + private val layout: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("column_id") + @ExcludeMissing + columnId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("position") + @ExcludeMissing + position: JsonField = JsonMissing.of(), + @JsonProperty("layout") @ExcludeMissing layout: JsonField = JsonMissing.of(), + ) : this(columnId, objectType, position, layout, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 columnId(): String = columnId.getRequired("column_id") + + /** + * @throws BraintrustInvalidDataException 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 objectType(): String = objectType.getRequired("object_type") + + /** + * @throws BraintrustInvalidDataException 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 position(): String = position.getRequired("position") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun layout(): Layout? = layout.getNullable("layout") + + /** + * Returns the raw JSON value of [columnId]. + * + * Unlike [columnId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("column_id") @ExcludeMissing fun _columnId(): JsonField = columnId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [position]. + * + * Unlike [position], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("position") @ExcludeMissing fun _position(): JsonField = position + + /** + * Returns the raw JSON value of [layout]. + * + * Unlike [layout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("layout") @ExcludeMissing fun _layout(): JsonField = layout + + @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 [SpanFieldOrder]. + * + * The following fields are required: + * ```kotlin + * .columnId() + * .objectType() + * .position() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [SpanFieldOrder]. */ + class Builder internal constructor() { + + private var columnId: JsonField? = null + private var objectType: JsonField? = null + private var position: JsonField? = null + private var layout: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(spanFieldOrder: SpanFieldOrder) = apply { + columnId = spanFieldOrder.columnId + objectType = spanFieldOrder.objectType + position = spanFieldOrder.position + layout = spanFieldOrder.layout + additionalProperties = spanFieldOrder.additionalProperties.toMutableMap() + } + + fun columnId(columnId: String) = columnId(JsonField.of(columnId)) + + /** + * Sets [Builder.columnId] to an arbitrary JSON value. + * + * You should usually call [Builder.columnId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun columnId(columnId: JsonField) = apply { this.columnId = columnId } + + fun objectType(objectType: String) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { this.objectType = objectType } + + fun position(position: String) = position(JsonField.of(position)) + + /** + * Sets [Builder.position] to an arbitrary JSON value. + * + * You should usually call [Builder.position] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun position(position: JsonField) = apply { this.position = position } + + fun layout(layout: Layout?) = layout(JsonField.ofNullable(layout)) + + /** + * Sets [Builder.layout] to an arbitrary JSON value. + * + * You should usually call [Builder.layout] with a well-typed [Layout] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun layout(layout: JsonField) = apply { this.layout = layout } + + 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 [SpanFieldOrder]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .columnId() + * .objectType() + * .position() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanFieldOrder = + SpanFieldOrder( + checkRequired("columnId", columnId), + checkRequired("objectType", objectType), + checkRequired("position", position), + layout, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SpanFieldOrder = apply { + if (validated) { + return@apply + } + + columnId() + objectType() + position() + layout()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (columnId.asKnown() == null) 0 else 1) + + (if (objectType.asKnown() == null) 0 else 1) + + (if (position.asKnown() == null) 0 else 1) + + (layout.asKnown()?.validity() ?: 0) + + class Layout @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 { + + val FULL = of("full") + + val TWO_COLUMN = of("two_column") + + fun of(value: String) = Layout(JsonField.of(value)) + } + + /** An enum containing [Layout]'s known values. */ + enum class Known { + FULL, + TWO_COLUMN, + } + + /** + * An enum containing [Layout]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Layout] 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 { + FULL, + TWO_COLUMN, + /** + * An enum member indicating that [Layout] 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) { + FULL -> Value.FULL + TWO_COLUMN -> Value.TWO_COLUMN + 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + FULL -> Known.FULL + TWO_COLUMN -> Known.TWO_COLUMN + else -> throw BraintrustInvalidDataException("Unknown Layout: $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 BraintrustInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Layout = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Layout && 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 SpanFieldOrder && + columnId == other.columnId && + objectType == other.objectType && + position == other.position && + layout == other.layout && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(columnId, objectType, position, layout, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SpanFieldOrder{columnId=$columnId, objectType=$objectType, position=$position, layout=$layout, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectSettings && + baselineExperimentId == other.baselineExperimentId && + comparisonKey == other.comparisonKey && + spanFieldOrder == other.spanFieldOrder && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(baselineExperimentId, comparisonKey, spanFieldOrder, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectSettings{baselineExperimentId=$baselineExperimentId, comparisonKey=$comparisonKey, spanFieldOrder=$spanFieldOrder, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTag.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTag.kt index 3b3b10ab..fbbe9978 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTag.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTag.kt @@ -6,235 +6,389 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects /** * A project tag is a user-configured tag for tracking and filtering your experiments, logs, and * other data */ -@JsonDeserialize(builder = ProjectTag.Builder::class) -@NoAutoDetect class ProjectTag +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, + private val name: JsonField, private val projectId: JsonField, private val userId: JsonField, + private val color: JsonField, private val created: JsonField, - private val name: JsonField, private val description: JsonField, - private val color: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the project tag */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + @JsonProperty("color") @ExcludeMissing color: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + ) : this(id, name, projectId, userId, color, created, description, mutableMapOf()) + + /** + * Unique identifier for the project tag + * + * @throws BraintrustInvalidDataException 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") - /** Unique identifier for the project that the project tag belongs under */ + /** + * Name of the project tag + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the project tag belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + /** + * @throws BraintrustInvalidDataException 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 userId(): String = userId.getRequired("user_id") - /** Date of project tag creation */ - fun created(): OffsetDateTime? = created.getNullable("created") - - /** Name of the project tag */ - fun name(): String = name.getRequired("name") - - /** Textual description of the project tag */ - fun description(): String? = description.getNullable("description") - - /** Color of the tag for the UI */ + /** + * Color of the tag for the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun color(): String? = color.getNullable("color") - /** Unique identifier for the project tag */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Unique identifier for the project that the project tag belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId - - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId - - /** Date of project tag creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** Name of the project tag */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Date of project tag creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") - /** Textual description of the project tag */ - @JsonProperty("description") @ExcludeMissing fun _description() = description + /** + * Textual description of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - /** Color of the tag for the UI */ - @JsonProperty("color") @ExcludeMissing fun _color() = color + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + /** + * Returns the raw JSON value of [color]. + * + * Unlike [color], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("color") @ExcludeMissing fun _color(): JsonField = color + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * 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 + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ProjectTag = apply { - if (!validated) { - id() - projectId() - userId() - created() - name() - description() - color() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectTag && - this.id == other.id && - this.projectId == other.projectId && - this.userId == other.userId && - this.created == other.created && - this.name == other.name && - this.description == other.description && - this.color == other.color && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - projectId, - userId, - created, - name, - description, - color, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ProjectTag{id=$id, projectId=$projectId, userId=$userId, created=$created, name=$name, description=$description, color=$color, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ProjectTag]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .userId() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ProjectTag]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var projectId: JsonField? = null + private var userId: JsonField? = null + private var color: JsonField = JsonMissing.of() private var created: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() private var description: JsonField = JsonMissing.of() - private var color: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(projectTag: ProjectTag) = apply { - this.id = projectTag.id - this.projectId = projectTag.projectId - this.userId = projectTag.userId - this.created = projectTag.created - this.name = projectTag.name - this.description = projectTag.description - this.color = projectTag.color - additionalProperties(projectTag.additionalProperties) + id = projectTag.id + name = projectTag.name + projectId = projectTag.projectId + userId = projectTag.userId + color = projectTag.color + created = projectTag.created + description = projectTag.description + additionalProperties = projectTag.additionalProperties.toMutableMap() } /** Unique identifier for the project tag */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the project tag */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } + + /** Name of the project tag */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } /** Unique identifier for the project that the project tag belongs under */ fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Unique identifier for the project that the project tag belongs under */ - @JsonProperty("project_id") - @ExcludeMissing + /** + * 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 userId(userId: String) = userId(JsonField.of(userId)) - @JsonProperty("user_id") - @ExcludeMissing + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun userId(userId: JsonField) = apply { this.userId = userId } - /** Date of project tag creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** Color of the tag for the UI */ + fun color(color: String?) = color(JsonField.ofNullable(color)) + + /** + * Sets [Builder.color] to an arbitrary JSON value. + * + * You should usually call [Builder.color] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun color(color: JsonField) = apply { this.color = color } /** Date of project tag creation */ - @JsonProperty("created") - @ExcludeMissing + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } - /** Name of the project tag */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the project tag */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - /** Textual description of the project tag */ - fun description(description: String) = description(JsonField.of(description)) - - /** Textual description of the project tag */ - @JsonProperty("description") - @ExcludeMissing + fun description(description: String?) = description(JsonField.ofNullable(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 } - /** Color of the tag for the UI */ - fun color(color: String) = color(JsonField.of(color)) - - /** Color of the tag for the UI */ - @JsonProperty("color") - @ExcludeMissing - fun color(color: JsonField) = apply { this.color = color } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ProjectTag]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .userId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ProjectTag = ProjectTag( - id, - projectId, - userId, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("userId", userId), + color, created, - name, description, - color, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): ProjectTag = apply { + if (validated) { + return@apply + } + + id() + name() + projectId() + userId() + color() + created() + description() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) + + (if (color.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectTag && + id == other.id && + name == other.name && + projectId == other.projectId && + userId == other.userId && + color == other.color && + created == other.created && + description == other.description && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, name, projectId, userId, color, created, description, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectTag{id=$id, name=$name, projectId=$projectId, userId=$userId, color=$color, created=$created, description=$description, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagCreateParams.kt index 2a58ac4a..df10a0a9 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagCreateParams.kt @@ -3,309 +3,620 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new project_tag. If there is an existing project_tag in the project with the same name + * as the one specified in the request, will return the existing project_tag unmodified + */ class ProjectTagCreateParams -constructor( - private val name: String, - private val projectId: String, - private val color: String?, - private val description: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun projectId(): String = projectId - - fun color(): String? = color - - fun description(): String? = description - - internal fun getBody(): ProjectTagCreateBody { - return ProjectTagCreateBody( - name, - projectId, - color, - description, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the project tag + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the project tag belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Color of the tag for the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun color(): String? = body.color() + + /** + * Textual description of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [color]. + * + * Unlike [color], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _color(): JsonField = body._color() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + 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 [ProjectTagCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectTagCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = ProjectTagCreateBody.Builder::class) - @NoAutoDetect - class ProjectTagCreateBody - internal constructor( - private val name: String?, - private val projectId: String?, - private val color: String?, - private val description: String?, - private val additionalProperties: Map, - ) { + internal fun from(projectTagCreateParams: ProjectTagCreateParams) = apply { + body = projectTagCreateParams.body.toBuilder() + additionalHeaders = projectTagCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = projectTagCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [projectId] + * - [color] + * - [description] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the project tag */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the project tag belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** Color of the tag for the UI */ - @JsonProperty("color") fun color(): String? = color + fun color(color: String?) = apply { body.color(color) } + + /** + * Sets [Builder.color] to an arbitrary JSON value. + * + * You should usually call [Builder.color] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun color(color: JsonField) = apply { body.color(color) } /** Textual description of the project tag */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(description) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * 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 { body.description(description) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ProjectTagCreateBody && - this.name == other.name && - this.projectId == other.projectId && - this.color == other.color && - this.description == other.description && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - projectId, - color, - description, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "ProjectTagCreateBody{name=$name, projectId=$projectId, color=$color, description=$description, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var name: String? = null - private var projectId: String? = null - private var color: String? = null - private var description: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectTagCreateBody: ProjectTagCreateBody) = apply { - this.name = projectTagCreateBody.name - this.projectId = projectTagCreateBody.projectId - this.color = projectTagCreateBody.color - this.description = projectTagCreateBody.description - additionalProperties(projectTagCreateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the project tag */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Unique identifier for the project that the project tag belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Color of the tag for the UI */ - @JsonProperty("color") fun color(color: String) = apply { this.color = color } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Textual description of the project tag */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): ProjectTagCreateBody = - ProjectTagCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - color, - description, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ProjectTagCreateParams && - this.name == other.name && - this.projectId == other.projectId && - this.color == other.color && - this.description == other.description && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ProjectTagCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectTagCreateParams = + ProjectTagCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - projectId, - color, - description, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "ProjectTagCreateParams{name=$name, projectId=$projectId, color=$color, description=$description, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val projectId: JsonField, + private val color: JsonField, + private val description: JsonField, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("color") @ExcludeMissing color: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + ) : this(name, projectId, color, description, mutableMapOf()) + + /** + * Name of the project tag + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the project tag belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * Color of the tag for the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun color(): String? = color.getNullable("color") + + /** + * Textual description of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [color]. + * + * Unlike [color], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("color") @ExcludeMissing fun _color(): JsonField = color + + /** + * 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 + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @NoAutoDetect - class Builder { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var name: String? = null - private var projectId: String? = null - private var color: String? = null - private var description: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(projectTagCreateParams: ProjectTagCreateParams) = apply { - this.name = projectTagCreateParams.name - this.projectId = projectTagCreateParams.projectId - this.color = projectTagCreateParams.color - this.description = projectTagCreateParams.description - additionalQueryParams(projectTagCreateParams.additionalQueryParams) - additionalHeaders(projectTagCreateParams.additionalHeaders) - additionalBodyProperties(projectTagCreateParams.additionalBodyProperties) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + */ + fun builder() = Builder() } - /** Name of the project tag */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Unique identifier for the project that the project tag belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var name: JsonField? = null + private var projectId: JsonField? = null + private var color: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** Color of the tag for the UI */ - fun color(color: String) = apply { this.color = color } + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + color = body.color + description = body.description + additionalProperties = body.additionalProperties.toMutableMap() + } - /** Textual description of the project tag */ - fun description(description: String) = apply { this.description = description } + /** Name of the project tag */ + fun name(name: String) = name(JsonField.of(name)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Unique identifier for the project that the project tag belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * 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 putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** Color of the tag for the UI */ + fun color(color: String?) = color(JsonField.ofNullable(color)) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Sets [Builder.color] to an arbitrary JSON value. + * + * You should usually call [Builder.color] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun color(color: JsonField) = apply { this.color = color } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** Textual description of the project tag */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + 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: + * ```kotlin + * .name() + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + color, + description, + additionalProperties.toMutableMap(), + ) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + projectId() + color() + description() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (color.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + projectId == other.projectId && + color == other.color && + description == other.description && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(name, projectId, color, description, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): ProjectTagCreateParams = - ProjectTagCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - color, - description, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{name=$name, projectId=$projectId, color=$color, description=$description, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectTagCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectTagCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParams.kt index 8abfb478..3817d440 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParams.kt @@ -3,138 +3,167 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a project_tag object by its id */ class ProjectTagDeleteParams -constructor( - private val projectTagId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val projectTagId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun projectTagId(): String = projectTagId + /** ProjectTag id */ + fun projectTagId(): String? = projectTagId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectTagId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ProjectTagDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectTagDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectTagDeleteParams]. */ + class Builder internal constructor() { + + private var projectTagId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalHeaders(): Map> = additionalHeaders + internal fun from(projectTagDeleteParams: ProjectTagDeleteParams) = apply { + projectTagId = projectTagDeleteParams.projectTagId + additionalHeaders = projectTagDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = projectTagDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + projectTagDeleteParams.additionalBodyProperties.toMutableMap() + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + /** ProjectTag id */ + fun projectTagId(projectTagId: String?) = apply { this.projectTagId = projectTagId } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ProjectTagDeleteParams && - this.projectTagId == other.projectTagId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - projectTagId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "ProjectTagDeleteParams{projectTagId=$projectTagId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var projectTagId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(projectTagDeleteParams: ProjectTagDeleteParams) = apply { - this.projectTagId = projectTagDeleteParams.projectTagId - additionalQueryParams(projectTagDeleteParams.additionalQueryParams) - additionalHeaders(projectTagDeleteParams.additionalHeaders) - additionalBodyProperties(projectTagDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** ProjectTag id */ - fun projectTagId(projectTagId: String) = apply { this.projectTagId = projectTagId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +171,60 @@ constructor( 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 [ProjectTagDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectTagDeleteParams = ProjectTagDeleteParams( - checkNotNull(projectTagId) { "`projectTagId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + projectTagId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectTagId ?: "" + 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 ProjectTagDeleteParams && + projectTagId == other.projectTagId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash( + projectTagId, + additionalHeaders, + additionalQueryParams, + additionalBodyProperties, + ) + + override fun toString() = + "ProjectTagDeleteParams{projectTagId=$projectTagId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPage.kt index 3c6bf919..dbd48892 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPage.kt @@ -2,176 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.ProjectTagService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see ProjectTagService.list */ class ProjectTagListPage private constructor( - private val projectTagsService: ProjectTagService, + private val service: ProjectTagService, private val params: ProjectTagListParams, - private val response: Response, -) { + private val response: ProjectTagListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [ProjectTagListPageResponse], but gracefully handles missing data. + * + * @see ProjectTagListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectTagListPage && - this.projectTagsService == other.projectTagsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - projectTagsService, - params, - response, - ) - } - - override fun toString() = - "ProjectTagListPage{projectTagsService=$projectTagsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ProjectTagListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ProjectTagListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ProjectTagListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ProjectTagListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): ProjectTagListPage? { - return getNextPageParams()?.let { projectTagsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - projectTagsService: ProjectTagService, - params: ProjectTagListParams, - response: Response - ) = - ProjectTagListPage( - projectTagsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): ProjectTagListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ProjectTagListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ProjectTagListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ProjectTagListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ProjectTagListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ProjectTagService? = null + private var params: ProjectTagListParams? = null + private var response: ProjectTagListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(projectTagListPage: ProjectTagListPage) = apply { + service = projectTagListPage.service + params = projectTagListPage.params + response = projectTagListPage.response } - override fun toString() = - "ProjectTagListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ProjectTagService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ProjectTagListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ProjectTagListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ProjectTagListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectTagListPage = + ProjectTagListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ProjectTagListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ProjectTagListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ProjectTagListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPageAsync.kt index 39e891f7..89e7a367 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPageAsync.kt @@ -2,178 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.ProjectTagServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see ProjectTagServiceAsync.list */ class ProjectTagListPageAsync private constructor( - private val projectTagsService: ProjectTagServiceAsync, + private val service: ProjectTagServiceAsync, private val params: ProjectTagListParams, - private val response: Response, -) { + private val response: ProjectTagListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [ProjectTagListPageResponse], but gracefully handles missing data. + * + * @see ProjectTagListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectTagListPageAsync && - this.projectTagsService == other.projectTagsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - projectTagsService, - params, - response, - ) - } - - override fun toString() = - "ProjectTagListPageAsync{projectTagsService=$projectTagsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ProjectTagListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ProjectTagListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ProjectTagListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ProjectTagListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): ProjectTagListPageAsync? { - return getNextPageParams()?.let { projectTagsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of( - projectTagsService: ProjectTagServiceAsync, - params: ProjectTagListParams, - response: Response - ) = - ProjectTagListPageAsync( - projectTagsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): ProjectTagListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ProjectTagListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ProjectTagListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ProjectTagListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ProjectTagListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ProjectTagServiceAsync? = null + private var params: ProjectTagListParams? = null + private var response: ProjectTagListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(projectTagListPageAsync: ProjectTagListPageAsync) = apply { + service = projectTagListPageAsync.service + params = projectTagListPageAsync.params + response = projectTagListPageAsync.response } - override fun toString() = - "ProjectTagListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ProjectTagServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ProjectTagListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ProjectTagListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ProjectTagListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectTagListPageAsync = + ProjectTagListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ProjectTagListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ProjectTagListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ProjectTagListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPageResponse.kt new file mode 100644 index 00000000..2c6c5817 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 ProjectTagListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of project_tag objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [ProjectTagListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ProjectTagListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(projectTagListPageResponse: ProjectTagListPageResponse) = apply { + objects = projectTagListPageResponse.objects.map { it.toMutableList() } + additionalProperties = projectTagListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of project_tag objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [ProjectTag] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: ProjectTag) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [ProjectTagListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectTagListPageResponse = + ProjectTagListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ProjectTagListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectTagListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProjectTagListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListParams.kt index 82a62079..f99064d2 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all project_tags. The project_tags are sorted by creation date, with the most + * recently-created project_tags coming first + */ class ProjectTagListParams -constructor( +private constructor( private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, @@ -29,91 +23,67 @@ constructor( private val projectName: String?, private val projectTagName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Project id */ fun projectId(): String? = projectId + /** Name of the project to search for */ fun projectName(): String? = projectName + /** Name of the project_tag to search for */ fun projectTagName(): String? = projectTagName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.projectId?.let { params.put("project_id", listOf(it.toString())) } - this.projectName?.let { params.put("project_name", listOf(it.toString())) } - this.projectTagName?.let { params.put("project_tag_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProjectTagListParams && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.projectId == other.projectId && - this.projectName == other.projectName && - this.projectTagName == other.projectTagName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - ids, - limit, - orgName, - projectId, - projectName, - projectTagName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "ProjectTagListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, projectTagName=$projectTagName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): ProjectTagListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectTagListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ProjectTagListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var ids: Ids? = null @@ -123,20 +93,20 @@ constructor( private var projectName: String? = null private var projectTagName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(projectTagListParams: ProjectTagListParams) = apply { - this.endingBefore = projectTagListParams.endingBefore - this.ids = projectTagListParams.ids - this.limit = projectTagListParams.limit - this.orgName = projectTagListParams.orgName - this.projectId = projectTagListParams.projectId - this.projectName = projectTagListParams.projectName - this.projectTagName = projectTagListParams.projectTagName - this.startingAfter = projectTagListParams.startingAfter - additionalQueryParams(projectTagListParams.additionalQueryParams) - additionalHeaders(projectTagListParams.additionalHeaders) + endingBefore = projectTagListParams.endingBefore + ids = projectTagListParams.ids + limit = projectTagListParams.limit + orgName = projectTagListParams.orgName + projectId = projectTagListParams.projectId + projectName = projectTagListParams.projectName + projectTagName = projectTagListParams.projectTagName + startingAfter = projectTagListParams.startingAfter + additionalHeaders = projectTagListParams.additionalHeaders.toBuilder() + additionalQueryParams = projectTagListParams.additionalQueryParams.toBuilder() } /** @@ -146,40 +116,41 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String?) = apply { this.projectId = projectId } /** Name of the project to search for */ - fun projectName(projectName: String) = apply { this.projectName = projectName } + fun projectName(projectName: String?) = apply { this.projectName = projectName } /** Name of the project_tag to search for */ - fun projectTagName(projectTagName: String) = apply { this.projectTagName = projectTagName } + fun projectTagName(projectTagName: String?) = apply { this.projectTagName = projectTagName } /** * Pagination cursor id. @@ -188,48 +159,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ProjectTagListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectTagListParams = ProjectTagListParams( endingBefore, @@ -240,22 +274,48 @@ constructor( projectName, projectTagName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + projectId?.let { put("project_id", it) } + projectName?.let { put("project_name", it) } + projectTagName?.let { put("project_tag_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -268,93 +328,78 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is ProjectTagListParams && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + projectId == other.projectId && + projectName == other.projectName && + projectTagName == other.projectTagName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + ids, + limit, + orgName, + projectId, + projectName, + projectTagName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "ProjectTagListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, projectTagName=$projectTagName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParams.kt index a5ab8187..255caa60 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParams.kt @@ -3,309 +3,621 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create or replace project_tag. If there is an existing project_tag in the project with the same + * name as the one specified in the request, will replace the existing project_tag with the provided + * fields + */ class ProjectTagReplaceParams -constructor( - private val name: String, - private val projectId: String, - private val color: String?, - private val description: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun projectId(): String = projectId - - fun color(): String? = color - - fun description(): String? = description - - internal fun getBody(): ProjectTagReplaceBody { - return ProjectTagReplaceBody( - name, - projectId, - color, - description, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the project tag + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the project tag belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Color of the tag for the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun color(): String? = body.color() + + /** + * Textual description of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [color]. + * + * Unlike [color], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _color(): JsonField = body._color() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + 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 [ProjectTagReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectTagReplaceParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = ProjectTagReplaceBody.Builder::class) - @NoAutoDetect - class ProjectTagReplaceBody - internal constructor( - private val name: String?, - private val projectId: String?, - private val color: String?, - private val description: String?, - private val additionalProperties: Map, - ) { + internal fun from(projectTagReplaceParams: ProjectTagReplaceParams) = apply { + body = projectTagReplaceParams.body.toBuilder() + additionalHeaders = projectTagReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = projectTagReplaceParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [projectId] + * - [color] + * - [description] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the project tag */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the project tag belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** Color of the tag for the UI */ - @JsonProperty("color") fun color(): String? = color + fun color(color: String?) = apply { body.color(color) } + + /** + * Sets [Builder.color] to an arbitrary JSON value. + * + * You should usually call [Builder.color] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun color(color: JsonField) = apply { body.color(color) } /** Textual description of the project tag */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(description) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * 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 { body.description(description) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ProjectTagReplaceBody && - this.name == other.name && - this.projectId == other.projectId && - this.color == other.color && - this.description == other.description && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - projectId, - color, - description, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "ProjectTagReplaceBody{name=$name, projectId=$projectId, color=$color, description=$description, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var name: String? = null - private var projectId: String? = null - private var color: String? = null - private var description: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectTagReplaceBody: ProjectTagReplaceBody) = apply { - this.name = projectTagReplaceBody.name - this.projectId = projectTagReplaceBody.projectId - this.color = projectTagReplaceBody.color - this.description = projectTagReplaceBody.description - additionalProperties(projectTagReplaceBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the project tag */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Unique identifier for the project that the project tag belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Color of the tag for the UI */ - @JsonProperty("color") fun color(color: String) = apply { this.color = color } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Textual description of the project tag */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): ProjectTagReplaceBody = - ProjectTagReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - color, - description, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ProjectTagReplaceParams && - this.name == other.name && - this.projectId == other.projectId && - this.color == other.color && - this.description == other.description && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ProjectTagReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProjectTagReplaceParams = + ProjectTagReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - projectId, - color, - description, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "ProjectTagReplaceParams{name=$name, projectId=$projectId, color=$color, description=$description, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val projectId: JsonField, + private val color: JsonField, + private val description: JsonField, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("color") @ExcludeMissing color: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + ) : this(name, projectId, color, description, mutableMapOf()) + + /** + * Name of the project tag + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the project tag belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * Color of the tag for the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun color(): String? = color.getNullable("color") + + /** + * Textual description of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [color]. + * + * Unlike [color], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("color") @ExcludeMissing fun _color(): JsonField = color + + /** + * 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 + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @NoAutoDetect - class Builder { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var name: String? = null - private var projectId: String? = null - private var color: String? = null - private var description: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(projectTagReplaceParams: ProjectTagReplaceParams) = apply { - this.name = projectTagReplaceParams.name - this.projectId = projectTagReplaceParams.projectId - this.color = projectTagReplaceParams.color - this.description = projectTagReplaceParams.description - additionalQueryParams(projectTagReplaceParams.additionalQueryParams) - additionalHeaders(projectTagReplaceParams.additionalHeaders) - additionalBodyProperties(projectTagReplaceParams.additionalBodyProperties) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * ``` + */ + fun builder() = Builder() } - /** Name of the project tag */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Unique identifier for the project that the project tag belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var name: JsonField? = null + private var projectId: JsonField? = null + private var color: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** Color of the tag for the UI */ - fun color(color: String) = apply { this.color = color } + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + color = body.color + description = body.description + additionalProperties = body.additionalProperties.toMutableMap() + } - /** Textual description of the project tag */ - fun description(description: String) = apply { this.description = description } + /** Name of the project tag */ + fun name(name: String) = name(JsonField.of(name)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Unique identifier for the project that the project tag belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * 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 putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** Color of the tag for the UI */ + fun color(color: String?) = color(JsonField.ofNullable(color)) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Sets [Builder.color] to an arbitrary JSON value. + * + * You should usually call [Builder.color] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun color(color: JsonField) = apply { this.color = color } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** Textual description of the project tag */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + 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: + * ```kotlin + * .name() + * .projectId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + color, + description, + additionalProperties.toMutableMap(), + ) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + projectId() + color() + description() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (color.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + projectId == other.projectId && + color == other.color && + description == other.description && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(name, projectId, color, description, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): ProjectTagReplaceParams = - ProjectTagReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - color, - description, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{name=$name, projectId=$projectId, color=$color, description=$description, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectTagReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectTagReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParams.kt index f0e6a318..85008ea9 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParams.kt @@ -2,125 +2,189 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a project_tag object by its id */ class ProjectTagRetrieveParams -constructor( - private val projectTagId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val projectTagId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun projectTagId(): String = projectTagId + /** ProjectTag id */ + fun projectTagId(): String? = projectTagId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectTagId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): ProjectTagRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectTagRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectTagRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var projectTagId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(projectTagRetrieveParams: ProjectTagRetrieveParams) = apply { + projectTagId = projectTagRetrieveParams.projectTagId + additionalHeaders = projectTagRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = projectTagRetrieveParams.additionalQueryParams.toBuilder() } - return other is ProjectTagRetrieveParams && - this.projectTagId == other.projectTagId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** ProjectTag id */ + fun projectTagId(projectTagId: String?) = apply { this.projectTagId = projectTagId } - override fun hashCode(): Int { - return Objects.hash( - projectTagId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "ProjectTagRetrieveParams{projectTagId=$projectTagId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var projectTagId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(projectTagRetrieveParams: ProjectTagRetrieveParams) = apply { - this.projectTagId = projectTagRetrieveParams.projectTagId - additionalQueryParams(projectTagRetrieveParams.additionalQueryParams) - additionalHeaders(projectTagRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** ProjectTag id */ - fun projectTagId(projectTagId: String) = apply { this.projectTagId = projectTagId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [ProjectTagRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ProjectTagRetrieveParams = ProjectTagRetrieveParams( - checkNotNull(projectTagId) { "`projectTagId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + projectTagId, + additionalHeaders.build(), + additionalQueryParams.build(), ) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectTagId ?: "" + 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 ProjectTagRetrieveParams && + projectTagId == other.projectTagId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(projectTagId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectTagRetrieveParams{projectTagId=$projectTagId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParams.kt index 76d6d12a..cee9d9e5 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParams.kt @@ -3,302 +3,537 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update a project_tag object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ class ProjectTagUpdateParams -constructor( - private val projectTagId: String, - private val color: String?, - private val description: String?, - private val name: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun projectTagId(): String = projectTagId - - fun color(): String? = color - - fun description(): String? = description - - fun name(): String? = name - - internal fun getBody(): ProjectTagUpdateBody { - return ProjectTagUpdateBody( - color, - description, - name, - additionalBodyProperties, - ) - } +private constructor( + private val projectTagId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** ProjectTag id */ + fun projectTagId(): String? = projectTagId + + /** + * Color of the tag for the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun color(): String? = body.color() + + /** + * Textual description of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Name of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * Returns the raw JSON value of [color]. + * + * Unlike [color], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _color(): JsonField = body._color() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + 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) - internal fun getQueryParams(): Map> = additionalQueryParams + companion object { - internal fun getHeaders(): Map> = additionalHeaders + fun none(): ProjectTagUpdateParams = builder().build() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectTagId - else -> "" - } + /** Returns a mutable builder for constructing an instance of [ProjectTagUpdateParams]. */ + fun builder() = Builder() } - @JsonDeserialize(builder = ProjectTagUpdateBody.Builder::class) - @NoAutoDetect - class ProjectTagUpdateBody - internal constructor( - private val color: String?, - private val description: String?, - private val name: String?, - private val additionalProperties: Map, - ) { + /** A builder for [ProjectTagUpdateParams]. */ + class Builder internal constructor() { + + private var projectTagId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + internal fun from(projectTagUpdateParams: ProjectTagUpdateParams) = apply { + projectTagId = projectTagUpdateParams.projectTagId + body = projectTagUpdateParams.body.toBuilder() + additionalHeaders = projectTagUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = projectTagUpdateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** ProjectTag id */ + fun projectTagId(projectTagId: String?) = apply { this.projectTagId = projectTagId } + + /** + * 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: + * - [color] + * - [description] + * - [name] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Color of the tag for the UI */ - @JsonProperty("color") fun color(): String? = color + fun color(color: String?) = apply { body.color(color) } + + /** + * Sets [Builder.color] to an arbitrary JSON value. + * + * You should usually call [Builder.color] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun color(color: JsonField) = apply { body.color(color) } /** Textual description of the project tag */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** Name of the project tag */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is ProjectTagUpdateBody && - this.color == other.color && - this.description == other.description && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - color, - description, - name, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "ProjectTagUpdateBody{color=$color, description=$description, name=$name, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var color: String? = null - private var description: String? = null - private var name: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectTagUpdateBody: ProjectTagUpdateBody) = apply { - this.color = projectTagUpdateBody.color - this.description = projectTagUpdateBody.description - this.name = projectTagUpdateBody.name - additionalProperties(projectTagUpdateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Color of the tag for the UI */ - @JsonProperty("color") fun color(color: String) = apply { this.color = color } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Textual description of the project tag */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Name of the project tag */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): ProjectTagUpdateBody = - ProjectTagUpdateBody( - color, - description, - name, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ProjectTagUpdateParams && - this.projectTagId == other.projectTagId && - this.color == other.color && - this.description == other.description && - this.name == other.name && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ProjectTagUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ProjectTagUpdateParams = + ProjectTagUpdateParams( + projectTagId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - projectTagId, - color, - description, - name, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "ProjectTagUpdateParams{projectTagId=$projectTagId, color=$color, description=$description, name=$name, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectTagId ?: "" + else -> "" + } - fun toBuilder() = Builder().from(this) + override fun _headers(): Headers = additionalHeaders - companion object { + override fun _queryParams(): QueryParams = additionalQueryParams - fun builder() = Builder() - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val color: JsonField, + private val description: JsonField, + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { - @NoAutoDetect - class Builder { + @JsonCreator + private constructor( + @JsonProperty("color") @ExcludeMissing color: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(color, description, name, mutableMapOf()) + + /** + * Color of the tag for the UI + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun color(): String? = color.getNullable("color") + + /** + * Textual description of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Name of the project tag + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * Returns the raw JSON value of [color]. + * + * Unlike [color], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("color") @ExcludeMissing fun _color(): JsonField = color + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - private var projectTagId: String? = null - private var color: String? = null - private var description: String? = null - private var name: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - internal fun from(projectTagUpdateParams: ProjectTagUpdateParams) = apply { - this.projectTagId = projectTagUpdateParams.projectTagId - this.color = projectTagUpdateParams.color - this.description = projectTagUpdateParams.description - this.name = projectTagUpdateParams.name - additionalQueryParams(projectTagUpdateParams.additionalQueryParams) - additionalHeaders(projectTagUpdateParams.additionalHeaders) - additionalBodyProperties(projectTagUpdateParams.additionalBodyProperties) + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - /** ProjectTag id */ - fun projectTagId(projectTagId: String) = apply { this.projectTagId = projectTagId } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Color of the tag for the UI */ - fun color(color: String) = apply { this.color = color } + private var color: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** Textual description of the project tag */ - fun description(description: String) = apply { this.description = description } + internal fun from(body: Body) = apply { + color = body.color + description = body.description + name = body.name + additionalProperties = body.additionalProperties.toMutableMap() + } - /** Name of the project tag */ - fun name(name: String) = apply { this.name = name } + /** Color of the tag for the UI */ + fun color(color: String?) = color(JsonField.ofNullable(color)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.color] to an arbitrary JSON value. + * + * You should usually call [Builder.color] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun color(color: JsonField) = apply { this.color = color } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Textual description of the project tag */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** Name of the project tag */ + fun name(name: String?) = name(JsonField.ofNullable(name)) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + 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(color, description, name, additionalProperties.toMutableMap()) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + color() + description() + name() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (color.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + color == other.color && + description == other.description && + name == other.name && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(color, description, name, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): ProjectTagUpdateParams = - ProjectTagUpdateParams( - checkNotNull(projectTagId) { "`projectTagId` is required but was not set" }, - color, - description, - name, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{color=$color, description=$description, name=$name, additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectTagUpdateParams && + projectTagId == other.projectTagId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(projectTagId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectTagUpdateParams{projectTagId=$projectTagId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectUpdateParams.kt index 88eccf6d..be1ad880 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ProjectUpdateParams.kt @@ -3,287 +3,479 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update a project object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class ProjectUpdateParams -constructor( - private val projectId: String, - private val name: String?, - private val settings: ProjectSettings?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun projectId(): String = projectId - - fun name(): String? = name - - fun settings(): ProjectSettings? = settings - - internal fun getBody(): ProjectUpdateBody { - return ProjectUpdateBody( - name, - settings, - additionalBodyProperties, - ) +private constructor( + private val projectId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Project id */ + fun projectId(): String? = projectId + + /** + * Name of the project + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * Project settings. Patch operations replace all settings, so make sure you include all + * settings you want to keep. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun settings(): ProjectSettings? = body.settings() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [settings]. + * + * Unlike [settings], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _settings(): JsonField = body._settings() + + 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 { + + fun none(): ProjectUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ProjectUpdateParams]. */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [ProjectUpdateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var projectId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> projectId - else -> "" + internal fun from(projectUpdateParams: ProjectUpdateParams) = apply { + projectId = projectUpdateParams.projectId + body = projectUpdateParams.body.toBuilder() + additionalHeaders = projectUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = projectUpdateParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = ProjectUpdateBody.Builder::class) - @NoAutoDetect - class ProjectUpdateBody - internal constructor( - private val name: String?, - private val settings: ProjectSettings?, - private val additionalProperties: Map, - ) { + /** Project id */ + fun projectId(projectId: String?) = apply { this.projectId = projectId } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [settings] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the project */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** * Project settings. Patch operations replace all settings, so make sure you include all * settings you want to keep. */ - @JsonProperty("settings") fun settings(): ProjectSettings? = settings + fun settings(settings: ProjectSettings?) = apply { body.settings(settings) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.settings] to an arbitrary JSON value. + * + * You should usually call [Builder.settings] with a well-typed [ProjectSettings] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun settings(settings: JsonField) = apply { body.settings(settings) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is ProjectUpdateBody && - this.name == other.name && - this.settings == other.settings && - this.additionalProperties == other.additionalProperties + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - settings, - additionalProperties, - ) - } - return hashCode + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - override fun toString() = - "ProjectUpdateBody{name=$name, settings=$settings, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun builder() = Builder() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var name: String? = null - private var settings: ProjectSettings? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(projectUpdateBody: ProjectUpdateBody) = apply { - this.name = projectUpdateBody.name - this.settings = projectUpdateBody.settings - additionalProperties(projectUpdateBody.additionalProperties) - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the project */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** - * Project settings. Patch operations replace all settings, so make sure you include all - * settings you want to keep. - */ - @JsonProperty("settings") - fun settings(settings: ProjectSettings) = apply { this.settings = settings } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun build(): ProjectUpdateBody = - ProjectUpdateBody( - name, - settings, - additionalProperties.toUnmodifiable(), - ) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - return other is ProjectUpdateParams && - this.projectId == other.projectId && - this.name == other.name && - this.settings == other.settings && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun hashCode(): Int { - return Objects.hash( - projectId, - name, - settings, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - override fun toString() = - "ProjectUpdateParams{projectId=$projectId, name=$name, settings=$settings, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun toBuilder() = Builder().from(this) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - companion object { + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun builder() = Builder() - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - @NoAutoDetect - class Builder { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - private var projectId: String? = null - private var name: String? = null - private var settings: ProjectSettings? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + /** + * Returns an immutable instance of [ProjectUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ProjectUpdateParams = + ProjectUpdateParams( + projectId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } - internal fun from(projectUpdateParams: ProjectUpdateParams) = apply { - this.projectId = projectUpdateParams.projectId - this.name = projectUpdateParams.name - this.settings = projectUpdateParams.settings - additionalQueryParams(projectUpdateParams.additionalQueryParams) - additionalHeaders(projectUpdateParams.additionalHeaders) - additionalBodyProperties(projectUpdateParams.additionalBodyProperties) + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> projectId ?: "" + else -> "" } - /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + override fun _headers(): Headers = additionalHeaders - /** Name of the project */ - fun name(name: String) = apply { this.name = name } + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val settings: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("settings") + @ExcludeMissing + settings: JsonField = JsonMissing.of(), + ) : this(name, settings, mutableMapOf()) + + /** + * Name of the project + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") /** * Project settings. Patch operations replace all settings, so make sure you include all * settings you want to keep. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun settings(settings: ProjectSettings) = apply { this.settings = settings } + fun settings(): ProjectSettings? = settings.getNullable("settings") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Returns the raw JSON value of [settings]. + * + * Unlike [settings], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("settings") + @ExcludeMissing + fun _settings(): JsonField = settings - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun toBuilder() = Builder().from(this) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + companion object { - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + private var name: JsonField = JsonMissing.of() + private var settings: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + internal fun from(body: Body) = apply { + name = body.name + settings = body.settings + additionalProperties = body.additionalProperties.toMutableMap() + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** Name of the project */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Project settings. Patch operations replace all settings, so make sure you include all + * settings you want to keep. + */ + fun settings(settings: ProjectSettings?) = settings(JsonField.ofNullable(settings)) + + /** + * Sets [Builder.settings] to an arbitrary JSON value. + * + * You should usually call [Builder.settings] with a well-typed [ProjectSettings] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun settings(settings: JsonField) = apply { this.settings = settings } + + 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(name, settings, additionalProperties.toMutableMap()) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + settings()?.validate() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): ProjectUpdateParams = - ProjectUpdateParams( - checkNotNull(projectId) { "`projectId` is required but was not set" }, - name, - settings, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (settings.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + settings == other.settings && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, settings, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, settings=$settings, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProjectUpdateParams && + projectId == other.projectId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(projectId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ProjectUpdateParams{projectId=$projectId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Prompt.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Prompt.kt index 542e91d5..80bc1f61 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Prompt.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Prompt.kt @@ -7,242 +7,352 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = Prompt.Builder::class) -@NoAutoDetect class Prompt +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val _xactId: JsonField, - private val projectId: JsonField, private val logId: JsonField, - private val orgId: JsonField, private val name: JsonField, + private val orgId: JsonField, + private val projectId: JsonField, private val slug: JsonField, - private val description: JsonField, private val created: JsonField, + private val description: JsonField, + private val functionType: JsonField, + private val metadata: JsonField, private val promptData: JsonField, private val tags: JsonField>, - private val metadata: JsonField, - private val functionType: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("_xact_id") @ExcludeMissing _xactId: JsonField = JsonMissing.of(), + @JsonProperty("log_id") @ExcludeMissing logId: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("function_type") + @ExcludeMissing + functionType: JsonField = JsonMissing.of(), + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this( + id, + _xactId, + logId, + name, + orgId, + projectId, + slug, + created, + description, + functionType, + metadata, + promptData, + tags, + mutableMapOf(), + ) - /** Unique identifier for the prompt */ + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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") /** * The transaction id of an event is unique to the network operation that processed the event * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve * a versioned snapshot of the prompt (see the `version` parameter) + * + * @throws BraintrustInvalidDataException 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 _xactId(): String = _xactId.getRequired("_xact_id") - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(): String = projectId.getRequired("project_id") - - /** A literal 'p' which identifies the object as a project prompt */ + /** + * A literal 'p' which identifies the object as a project prompt + * + * @throws BraintrustInvalidDataException 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 logId(): LogId = logId.getRequired("log_id") - /** Unique identifier for the organization */ + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the organization + * + * @throws BraintrustInvalidDataException 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 orgId(): String = orgId.getRequired("org_id") - /** Name of the prompt */ - fun name(): String = name.getRequired("name") + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") - /** Unique identifier for the prompt */ + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") - /** Textual description of the prompt */ - fun description(): String? = description.getNullable("description") - - /** Date of prompt creation */ + /** + * Date of prompt creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** The prompt, model, and its parameters */ - fun promptData(): PromptData? = promptData.getNullable("prompt_data") - - /** A list of tags for the prompt */ - fun tags(): List? = tags.getNullable("tags") - - /** User-controlled metadata about the prompt */ - fun metadata(): Metadata? = metadata.getNullable("metadata") + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun functionType(): FunctionType? = functionType.getNullable("function_type") - /** Unique identifier for the prompt */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - /** - * The transaction id of an event is unique to the network operation that processed the event - * insertion. Transaction ids are monotonically increasing over time and can be used to retrieve - * a versioned snapshot of the prompt (see the `version` parameter) + * User-controlled metadata about the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("_xact_id") @ExcludeMissing fun __xactId() = _xactId + fun metadata(): Metadata? = metadata.getNullable("metadata") - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") - /** A literal 'p' which identifies the object as a project prompt */ - @JsonProperty("log_id") @ExcludeMissing fun _logId() = logId + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") - /** Unique identifier for the organization */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId + /** + * 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 - /** Name of the prompt */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [_xactId]. + * + * Unlike [_xactId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("_xact_id") @ExcludeMissing fun __xactId(): JsonField = _xactId - /** Unique identifier for the prompt */ - @JsonProperty("slug") @ExcludeMissing fun _slug() = slug + /** + * Returns the raw JSON value of [logId]. + * + * Unlike [logId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("log_id") @ExcludeMissing fun _logId(): JsonField = logId - /** Textual description of the prompt */ - @JsonProperty("description") @ExcludeMissing fun _description() = description + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Date of prompt creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") @ExcludeMissing fun _promptData() = promptData + /** + * 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 - /** A list of tags for the prompt */ - @JsonProperty("tags") @ExcludeMissing fun _tags() = tags + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug - /** User-controlled metadata about the prompt */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata() = metadata + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - @JsonProperty("function_type") @ExcludeMissing fun _functionType() = functionType + /** + * 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 - @JsonAnyGetter + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("function_type") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _functionType(): JsonField = functionType - fun validate(): Prompt = apply { - if (!validated) { - id() - _xactId() - projectId() - logId() - orgId() - name() - slug() - description() - created() - promptData()?.validate() - tags() - metadata()?.validate() - functionType() - validated = true - } - } + /** + * 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 - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") + @ExcludeMissing + fun _promptData(): JsonField = promptData - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags - return other is Prompt && - this.id == other.id && - this._xactId == other._xactId && - this.projectId == other.projectId && - this.logId == other.logId && - this.orgId == other.orgId && - this.name == other.name && - this.slug == other.slug && - this.description == other.description && - this.created == other.created && - this.promptData == other.promptData && - this.tags == other.tags && - this.metadata == other.metadata && - this.functionType == other.functionType && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - _xactId, - projectId, - logId, - orgId, - name, - slug, - description, - created, - promptData, - tags, - metadata, - functionType, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Prompt{id=$id, _xactId=$_xactId, projectId=$projectId, logId=$logId, orgId=$orgId, name=$name, slug=$slug, description=$description, created=$created, promptData=$promptData, tags=$tags, metadata=$metadata, functionType=$functionType, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Prompt]. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .logId() + * .name() + * .orgId() + * .projectId() + * .slug() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Prompt]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var _xactId: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var logId: JsonField = JsonMissing.of() - private var orgId: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var slug: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var _xactId: JsonField? = null + private var logId: JsonField? = null + private var name: JsonField? = null + private var orgId: JsonField? = null + private var projectId: JsonField? = null + private var slug: JsonField? = null private var created: JsonField = JsonMissing.of() - private var promptData: JsonField = JsonMissing.of() - private var tags: JsonField> = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() private var functionType: JsonField = JsonMissing.of() + private var metadata: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var tags: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(prompt: Prompt) = apply { - this.id = prompt.id - this._xactId = prompt._xactId - this.projectId = prompt.projectId - this.logId = prompt.logId - this.orgId = prompt.orgId - this.name = prompt.name - this.slug = prompt.slug - this.description = prompt.description - this.created = prompt.created - this.promptData = prompt.promptData - this.tags = prompt.tags - this.metadata = prompt.metadata - this.functionType = prompt.functionType - additionalProperties(prompt.additionalProperties) + id = prompt.id + _xactId = prompt._xactId + logId = prompt.logId + name = prompt.name + orgId = prompt.orgId + projectId = prompt.projectId + slug = prompt.slug + created = prompt.created + description = prompt.description + functionType = prompt.functionType + metadata = prompt.metadata + promptData = prompt.promptData + tags = prompt.tags.map { it.toMutableList() } + additionalProperties = prompt.additionalProperties.toMutableMap() } /** Unique identifier for the prompt */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the prompt */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } /** * The transaction id of an event is unique to the network operation that processed the @@ -252,219 +362,408 @@ private constructor( fun _xactId(_xactId: String) = _xactId(JsonField.of(_xactId)) /** - * The transaction id of an event is unique to the network operation that processed the - * event insertion. Transaction ids are monotonically increasing over time and can be used - * to retrieve a versioned snapshot of the prompt (see the `version` parameter) + * Sets [Builder._xactId] to an arbitrary JSON value. + * + * You should usually call [Builder._xactId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("_xact_id") - @ExcludeMissing fun _xactId(_xactId: JsonField) = apply { this._xactId = _xactId } - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") - @ExcludeMissing - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } - /** A literal 'p' which identifies the object as a project prompt */ fun logId(logId: LogId) = logId(JsonField.of(logId)) - /** A literal 'p' which identifies the object as a project prompt */ - @JsonProperty("log_id") - @ExcludeMissing + /** + * Sets [Builder.logId] to an arbitrary JSON value. + * + * You should usually call [Builder.logId] with a well-typed [LogId] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun logId(logId: JsonField) = apply { this.logId = logId } + /** Name of the prompt */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + /** Unique identifier for the organization */ fun orgId(orgId: String) = orgId(JsonField.of(orgId)) - /** Unique identifier for the organization */ - @JsonProperty("org_id") - @ExcludeMissing + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun orgId(orgId: JsonField) = apply { this.orgId = orgId } - /** Name of the prompt */ - fun name(name: String) = name(JsonField.of(name)) + /** Unique identifier for the project that the prompt belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** Name of the prompt */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + /** + * 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 } /** Unique identifier for the prompt */ fun slug(slug: String) = slug(JsonField.of(slug)) - /** Unique identifier for the prompt */ - @JsonProperty("slug") - @ExcludeMissing + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun slug(slug: JsonField) = apply { this.slug = slug } - /** Textual description of the prompt */ - fun description(description: String) = description(JsonField.of(description)) - - /** Textual description of the prompt */ - @JsonProperty("description") - @ExcludeMissing - fun description(description: JsonField) = apply { this.description = description } - /** Date of prompt creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) - /** Date of prompt creation */ - @JsonProperty("created") - @ExcludeMissing + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = promptData(JsonField.of(promptData)) + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(description)) - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - @ExcludeMissing - fun promptData(promptData: JsonField) = apply { this.promptData = promptData } + /** + * 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 } - /** A list of tags for the prompt */ - fun tags(tags: List) = tags(JsonField.of(tags)) + fun functionType(functionType: FunctionType?) = + functionType(JsonField.ofNullable(functionType)) - /** A list of tags for the prompt */ - @JsonProperty("tags") - @ExcludeMissing - fun tags(tags: JsonField>) = apply { this.tags = tags } + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + this.functionType = functionType + } /** User-controlled metadata about the prompt */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun metadata(metadata: Metadata?) = metadata(JsonField.ofNullable(metadata)) - /** User-controlled metadata about the prompt */ - @JsonProperty("metadata") - @ExcludeMissing + /** + * 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 functionType(functionType: FunctionType) = functionType(JsonField.of(functionType)) + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) - @JsonProperty("function_type") - @ExcludeMissing - fun functionType(functionType: JsonField) = apply { - this.functionType = functionType + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { this.promptData = promptData } + + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Prompt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ._xactId() + * .logId() + * .name() + * .orgId() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Prompt = Prompt( - id, - _xactId, - projectId, - logId, - orgId, - name, - slug, - description, + checkRequired("id", id), + checkRequired("_xactId", _xactId), + checkRequired("logId", logId), + checkRequired("name", name), + checkRequired("orgId", orgId), + checkRequired("projectId", projectId), + checkRequired("slug", slug), created, - promptData, - tags.map { it.toUnmodifiable() }, - metadata, + description, functionType, - additionalProperties.toUnmodifiable(), + metadata, + promptData, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } - class LogId - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Prompt = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + id() + _xactId() + logId().validate() + name() + orgId() + projectId() + slug() + created() + description() + functionType()?.validate() + metadata()?.validate() + promptData()?.validate() + tags() + validated = true + } - return other is LogId && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (_xactId.asKnown() == null) 0 else 1) + + (logId.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (functionType.asKnown()?.validity() ?: 0) + + (metadata.asKnown()?.validity() ?: 0) + + (promptData.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) - override fun toString() = value.toString() + /** A literal 'p' which identifies the object as a project prompt */ + class LogId @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 { - val P = LogId(JsonField.of("p")) + val P = of("p") fun of(value: String) = LogId(JsonField.of(value)) } + /** An enum containing [LogId]'s known values. */ enum class Known { - P, + P } + /** + * An enum containing [LogId]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [LogId] 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 { P, + /** An enum member indicating that [LogId] 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) { P -> Value.P 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { P -> Known.P else -> throw BraintrustInvalidDataException("Unknown LogId: $value") } - fun asString(): String = _value().asStringOrThrow() - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") - class FunctionType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): LogId = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FunctionType && this.value == other.value + return other is LogId && value == other.value } override fun hashCode() = value.hashCode() override fun toString() = value.toString() + } + + class FunctionType @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 { - val LLM = FunctionType(JsonField.of("llm")) + val LLM = of("llm") - val SCORER = FunctionType(JsonField.of("scorer")) + val SCORER = of("scorer") - val TASK = FunctionType(JsonField.of("task")) + val TASK = of("task") - val TOOL = FunctionType(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = FunctionType(JsonField.of(value)) } + /** An enum containing [FunctionType]'s known values. */ enum class Known { LLM, SCORER, @@ -472,14 +771,33 @@ private constructor( TOOL, } + /** + * An enum containing [FunctionType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [FunctionType] 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 { LLM, SCORER, TASK, TOOL, + /** + * An enum member indicating that [FunctionType] 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) { LLM -> Value.LLM @@ -489,6 +807,15 @@ private constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { LLM -> Known.LLM @@ -498,78 +825,199 @@ private constructor( else -> throw BraintrustInvalidDataException("Unknown FunctionType: $value") } - fun asString(): String = _value().asStringOrThrow() - } - - /** User-controlled metadata about the prompt */ - @JsonDeserialize(builder = Metadata.Builder::class) - @NoAutoDetect - class Metadata - private constructor( - private val additionalProperties: Map, - ) { + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): FunctionType = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + known() + validated = true + } - fun validate(): Metadata = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Metadata && this.additionalProperties == other.additionalProperties + return other is FunctionType && value == other.value } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + override fun hashCode() = value.hashCode() - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + override fun toString() = value.toString() + } + + /** User-controlled metadata about the prompt */ + 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]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metadata]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metadata: Metadata) = apply { - additionalProperties(metadata.additionalProperties) + additionalProperties = metadata.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metadata = Metadata(additionalProperties.toUnmodifiable()) + 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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is Prompt && + id == other.id && + _xactId == other._xactId && + logId == other.logId && + name == other.name && + orgId == other.orgId && + projectId == other.projectId && + slug == other.slug && + created == other.created && + description == other.description && + functionType == other.functionType && + metadata == other.metadata && + promptData == other.promptData && + tags == other.tags && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { + Objects.hash( + id, + _xactId, + logId, + name, + orgId, + projectId, + slug, + created, + description, + functionType, + metadata, + promptData, + tags, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Prompt{id=$id, _xactId=$_xactId, logId=$logId, name=$name, orgId=$orgId, projectId=$projectId, slug=$slug, created=$created, description=$description, functionType=$functionType, metadata=$metadata, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptCreateParams.kt index 9d4cf98e..ff076581 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptCreateParams.kt @@ -5,426 +5,865 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new prompt. If there is an existing prompt in the project with the same slug as the one + * specified in the request, will return the existing prompt unmodified + */ class PromptCreateParams -constructor( - private val name: String, - private val projectId: String, - private val slug: String, - private val description: String?, - private val functionType: FunctionType?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun projectId(): String = projectId - - fun slug(): String = slug - - fun description(): String? = description - - fun functionType(): FunctionType? = functionType - - fun promptData(): PromptData? = promptData - - fun tags(): List? = tags - - internal fun getBody(): PromptCreateBody { - return PromptCreateBody( - name, - projectId, - slug, - description, - functionType, - promptData, - tags, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = body.slug() + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionType(): FunctionType? = body.functionType() + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = body.promptData() + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = body.tags() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _slug(): JsonField = body._slug() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionType(): JsonField = body._functionType() + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _promptData(): JsonField = body._promptData() + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tags(): JsonField> = body._tags() + + 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 [PromptCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = PromptCreateBody.Builder::class) - @NoAutoDetect - class PromptCreateBody - internal constructor( - private val name: String?, - private val projectId: String?, - private val slug: String?, - private val description: String?, - private val functionType: FunctionType?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalProperties: Map, - ) { + /** A builder for [PromptCreateParams]. */ + class Builder internal constructor() { - private var hashCode: Int = 0 + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + internal fun from(promptCreateParams: PromptCreateParams) = apply { + body = promptCreateParams.body.toBuilder() + additionalHeaders = promptCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = promptCreateParams.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: + * - [name] + * - [projectId] + * - [slug] + * - [description] + * - [functionType] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the prompt */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(): String? = slug + fun slug(slug: String) = apply { body.slug(slug) } - /** Textual description of the prompt */ - @JsonProperty("description") fun description(): String? = description + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun slug(slug: JsonField) = apply { body.slug(slug) } - @JsonProperty("function_type") fun functionType(): FunctionType? = functionType + /** Textual description of the prompt */ + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + fun functionType(functionType: FunctionType?) = apply { body.functionType(functionType) } + + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + body.functionType(functionType) + } /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") fun promptData(): PromptData? = promptData + fun promptData(promptData: PromptData?) = apply { body.promptData(promptData) } + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { body.promptData(promptData) } /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(): List? = tags + fun tags(tags: List?) = apply { body.tags(tags) } + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { body.tags(tags) } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { body.addTag(tag) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is PromptCreateBody && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionType == other.functionType && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - projectId, - slug, - description, - functionType, - promptData, - tags, - additionalProperties, - ) - } - return hashCode + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "PromptCreateBody{name=$name, projectId=$projectId, slug=$slug, description=$description, functionType=$functionType, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionType: FunctionType? = null - private var promptData: PromptData? = null - private var tags: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(promptCreateBody: PromptCreateBody) = apply { - this.name = promptCreateBody.name - this.projectId = promptCreateBody.projectId - this.slug = promptCreateBody.slug - this.description = promptCreateBody.description - this.functionType = promptCreateBody.functionType - this.promptData = promptCreateBody.promptData - this.tags = promptCreateBody.tags - additionalProperties(promptCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the prompt */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(slug: String) = apply { this.slug = slug } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Textual description of the prompt */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("function_type") - fun functionType(functionType: FunctionType) = apply { - this.functionType = functionType - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(tags: List) = apply { this.tags = tags } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): PromptCreateBody = - PromptCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, - description, - functionType, - promptData, - tags?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is PromptCreateParams && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionType == other.functionType && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [PromptCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PromptCreateParams = + PromptCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - projectId, - slug, - description, - functionType, - promptData, - tags, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "PromptCreateParams{name=$name, projectId=$projectId, slug=$slug, description=$description, functionType=$functionType, promptData=$promptData, tags=$tags, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val projectId: JsonField, + private val slug: JsonField, + private val description: JsonField, + private val functionType: JsonField, + private val promptData: JsonField, + private val tags: JsonField>, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("function_type") + @ExcludeMissing + functionType: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this(name, projectId, slug, description, functionType, promptData, tags, mutableMapOf()) + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun functionType(): FunctionType? = functionType.getNullable("function_type") + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug + + /** + * 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 [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_type") + @ExcludeMissing + fun _functionType(): JsonField = functionType + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") + @ExcludeMissing + fun _promptData(): JsonField = promptData + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @NoAutoDetect - class Builder { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionType: FunctionType? = null - private var promptData: PromptData? = null - private var tags: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(promptCreateParams: PromptCreateParams) = apply { - this.name = promptCreateParams.name - this.projectId = promptCreateParams.projectId - this.slug = promptCreateParams.slug - this.description = promptCreateParams.description - this.functionType = promptCreateParams.functionType - this.promptData = promptCreateParams.promptData - this.tags(promptCreateParams.tags ?: listOf()) - additionalQueryParams(promptCreateParams.additionalQueryParams) - additionalHeaders(promptCreateParams.additionalHeaders) - additionalBodyProperties(promptCreateParams.additionalBodyProperties) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() } - /** Name of the prompt */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var name: JsonField? = null + private var projectId: JsonField? = null + private var slug: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var functionType: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - /** Unique identifier for the prompt */ - fun slug(slug: String) = apply { this.slug = slug } + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + slug = body.slug + description = body.description + functionType = body.functionType + promptData = body.promptData + tags = body.tags.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - /** Textual description of the prompt */ - fun description(description: String) = apply { this.description = description } + /** Name of the prompt */ + fun name(name: String) = name(JsonField.of(name)) - fun functionType(functionType: FunctionType) = apply { this.functionType = functionType } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + /** Unique identifier for the project that the prompt belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** A list of tags for the prompt */ - fun tags(tags: List) = apply { - this.tags.clear() - this.tags.addAll(tags) - } + /** + * 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 } - /** A list of tags for the prompt */ - fun addTag(tag: String) = apply { this.tags.add(tag) } + /** Unique identifier for the prompt */ + fun slug(slug: String) = slug(JsonField.of(slug)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun slug(slug: JsonField) = apply { this.slug = slug } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun functionType(functionType: FunctionType?) = + functionType(JsonField.ofNullable(functionType)) + + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + this.functionType = functionType + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { + this.promptData = promptData + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = + (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("slug", slug), + description, + functionType, + promptData, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply } - fun build(): PromptCreateParams = - PromptCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, - description, - functionType, - promptData, - if (tags.size == 0) null else tags.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + name() + projectId() + slug() + description() + functionType()?.validate() + promptData()?.validate() + tags() + validated = true + } - class FunctionType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (functionType.asKnown()?.validity() ?: 0) + + (promptData.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is FunctionType && this.value == other.value + return other is Body && + name == other.name && + projectId == other.projectId && + slug == other.slug && + description == other.description && + functionType == other.functionType && + promptData == other.promptData && + tags == other.tags && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash( + name, + projectId, + slug, + description, + functionType, + promptData, + tags, + additionalProperties, + ) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, projectId=$projectId, slug=$slug, description=$description, functionType=$functionType, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" + } + + class FunctionType @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 { - val LLM = FunctionType(JsonField.of("llm")) + val LLM = of("llm") - val SCORER = FunctionType(JsonField.of("scorer")) + val SCORER = of("scorer") - val TASK = FunctionType(JsonField.of("task")) + val TASK = of("task") - val TOOL = FunctionType(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = FunctionType(JsonField.of(value)) } + /** An enum containing [FunctionType]'s known values. */ enum class Known { LLM, SCORER, @@ -432,14 +871,33 @@ constructor( TOOL, } + /** + * An enum containing [FunctionType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [FunctionType] 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 { LLM, SCORER, TASK, TOOL, + /** + * An enum member indicating that [FunctionType] 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) { LLM -> Value.LLM @@ -449,6 +907,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { LLM -> Known.LLM @@ -458,6 +925,71 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown FunctionType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): FunctionType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FunctionType && 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 PromptCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "PromptCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptData.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptData.kt index 62313816..6b9f16bd 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptData.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptData.kt @@ -9,9 +9,11 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -24,2221 +26,749 @@ 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 /** The prompt, model, and its parameters */ -@JsonDeserialize(builder = PromptData.Builder::class) -@NoAutoDetect class PromptData +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val prompt: JsonField, - private val options: JsonField, + private val options: JsonField, + private val origin: JsonField, private val parser: JsonField, + private val prompt: JsonField, private val toolFunctions: JsonField>, - private val origin: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("options") + @ExcludeMissing + options: JsonField = JsonMissing.of(), + @JsonProperty("origin") @ExcludeMissing origin: JsonField = JsonMissing.of(), + @JsonProperty("parser") @ExcludeMissing parser: JsonField = JsonMissing.of(), + @JsonProperty("prompt") @ExcludeMissing prompt: JsonField = JsonMissing.of(), + @JsonProperty("tool_functions") + @ExcludeMissing + toolFunctions: JsonField> = JsonMissing.of(), + ) : this(options, origin, parser, prompt, toolFunctions, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): PromptOptions? = options.getNullable("options") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun origin(): Origin? = origin.getNullable("origin") - private var hashCode: Int = 0 + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun parser(): Parser? = parser.getNullable("parser") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun prompt(): Prompt? = prompt.getNullable("prompt") - fun options(): Options? = options.getNullable("options") - - fun parser(): Parser? = parser.getNullable("parser") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun toolFunctions(): List? = toolFunctions.getNullable("tool_functions") - fun origin(): Origin? = origin.getNullable("origin") - - @JsonProperty("prompt") @ExcludeMissing fun _prompt() = prompt - - @JsonProperty("options") @ExcludeMissing fun _options() = options - - @JsonProperty("parser") @ExcludeMissing fun _parser() = parser - - @JsonProperty("tool_functions") @ExcludeMissing fun _toolFunctions() = toolFunctions + /** + * 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 [origin]. + * + * Unlike [origin], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("origin") @ExcludeMissing fun _origin(): JsonField = origin + + /** + * Returns the raw JSON value of [parser]. + * + * Unlike [parser], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("parser") @ExcludeMissing fun _parser(): JsonField = parser + + /** + * Returns the raw JSON value of [prompt]. + * + * Unlike [prompt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt") @ExcludeMissing fun _prompt(): JsonField = prompt + + /** + * Returns the raw JSON value of [toolFunctions]. + * + * Unlike [toolFunctions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tool_functions") + @ExcludeMissing + fun _toolFunctions(): JsonField> = toolFunctions - @JsonProperty("origin") @ExcludeMissing fun _origin() = origin + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): PromptData = apply { - if (!validated) { - prompt() - options()?.validate() - parser()?.validate() - toolFunctions() - origin()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is PromptData && - this.prompt == other.prompt && - this.options == other.options && - this.parser == other.parser && - this.toolFunctions == other.toolFunctions && - this.origin == other.origin && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - prompt, - options, - parser, - toolFunctions, - origin, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "PromptData{prompt=$prompt, options=$options, parser=$parser, toolFunctions=$toolFunctions, origin=$origin, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [PromptData]. */ fun builder() = Builder() } - class Builder { + /** A builder for [PromptData]. */ + class Builder internal constructor() { - private var prompt: JsonField = JsonMissing.of() - private var options: JsonField = JsonMissing.of() - private var parser: JsonField = JsonMissing.of() - private var toolFunctions: JsonField> = JsonMissing.of() + private var options: JsonField = JsonMissing.of() private var origin: JsonField = JsonMissing.of() + private var parser: JsonField = JsonMissing.of() + private var prompt: JsonField = JsonMissing.of() + private var toolFunctions: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(promptData: PromptData) = apply { - this.prompt = promptData.prompt - this.options = promptData.options - this.parser = promptData.parser - this.toolFunctions = promptData.toolFunctions - this.origin = promptData.origin - additionalProperties(promptData.additionalProperties) + options = promptData.options + origin = promptData.origin + parser = promptData.parser + prompt = promptData.prompt + toolFunctions = promptData.toolFunctions.map { it.toMutableList() } + additionalProperties = promptData.additionalProperties.toMutableMap() } - fun prompt(prompt: Prompt) = prompt(JsonField.of(prompt)) + fun options(options: PromptOptions?) = options(JsonField.ofNullable(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [PromptOptions] 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 origin(origin: Origin?) = origin(JsonField.ofNullable(origin)) + + /** + * Sets [Builder.origin] to an arbitrary JSON value. + * + * You should usually call [Builder.origin] with a well-typed [Origin] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun origin(origin: JsonField) = apply { this.origin = origin } - @JsonProperty("prompt") - @ExcludeMissing - fun prompt(prompt: JsonField) = apply { this.prompt = prompt } + fun parser(parser: Parser?) = parser(JsonField.ofNullable(parser)) - fun options(options: Options) = options(JsonField.of(options)) + /** + * Sets [Builder.parser] to an arbitrary JSON value. + * + * You should usually call [Builder.parser] with a well-typed [Parser] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun parser(parser: JsonField) = apply { this.parser = parser } - @JsonProperty("options") - @ExcludeMissing - fun options(options: JsonField) = apply { this.options = options } + fun prompt(prompt: Prompt?) = prompt(JsonField.ofNullable(prompt)) - fun parser(parser: Parser) = parser(JsonField.of(parser)) + /** + * Sets [Builder.prompt] to an arbitrary JSON value. + * + * You should usually call [Builder.prompt] with a well-typed [Prompt] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun prompt(prompt: JsonField) = apply { this.prompt = prompt } - @JsonProperty("parser") - @ExcludeMissing - fun parser(parser: JsonField) = apply { this.parser = parser } + /** Alias for calling [prompt] with `Prompt.ofCompletion(completion)`. */ + fun prompt(completion: Prompt.Completion) = prompt(Prompt.ofCompletion(completion)) - fun toolFunctions(toolFunctions: List) = - toolFunctions(JsonField.of(toolFunctions)) + /** Alias for calling [prompt] with `Prompt.ofChat(chat)`. */ + fun prompt(chat: Prompt.Chat) = prompt(Prompt.ofChat(chat)) - @JsonProperty("tool_functions") - @ExcludeMissing + fun toolFunctions(toolFunctions: List?) = + toolFunctions(JsonField.ofNullable(toolFunctions)) + + /** + * Sets [Builder.toolFunctions] to an arbitrary JSON value. + * + * You should usually call [Builder.toolFunctions] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun toolFunctions(toolFunctions: JsonField>) = apply { - this.toolFunctions = toolFunctions + this.toolFunctions = toolFunctions.map { it.toMutableList() } } - fun origin(origin: Origin) = origin(JsonField.of(origin)) + /** + * Adds a single [ToolFunction] to [toolFunctions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addToolFunction(toolFunction: ToolFunction) = apply { + toolFunctions = + (toolFunctions ?: JsonField.of(mutableListOf())).also { + checkKnown("toolFunctions", it).add(toolFunction) + } + } - @JsonProperty("origin") - @ExcludeMissing - fun origin(origin: JsonField) = apply { this.origin = origin } + /** Alias for calling [addToolFunction] with `ToolFunction.ofFunction(function)`. */ + fun addToolFunction(function: ToolFunction.Function) = + addToolFunction(ToolFunction.ofFunction(function)) + + /** Alias for calling [addToolFunction] with `ToolFunction.ofGlobal(global)`. */ + fun addToolFunction(global: ToolFunction.Global) = + addToolFunction(ToolFunction.ofGlobal(global)) fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [PromptData]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): PromptData = PromptData( - prompt, options, - parser, - toolFunctions.map { it.toUnmodifiable() }, origin, - additionalProperties.toUnmodifiable(), + parser, + prompt, + (toolFunctions ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = Options.Builder::class) - @NoAutoDetect - class Options - private constructor( - private val model: JsonField, - private val params: JsonField, - private val position: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 + private var validated: Boolean = false - fun model(): String? = model.getNullable("model") + fun validate(): PromptData = apply { + if (validated) { + return@apply + } - fun params(): Params? = params.getNullable("params") + options()?.validate() + origin()?.validate() + parser()?.validate() + prompt()?.validate() + toolFunctions()?.forEach { it.validate() } + validated = true + } - fun position(): String? = position.getNullable("position") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @JsonProperty("model") @ExcludeMissing fun _model() = model + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (options.asKnown()?.validity() ?: 0) + + (origin.asKnown()?.validity() ?: 0) + + (parser.asKnown()?.validity() ?: 0) + + (prompt.asKnown()?.validity() ?: 0) + + (toolFunctions.asKnown()?.sumOf { it.validity().toInt() } ?: 0) - @JsonProperty("params") @ExcludeMissing fun _params() = params + class Origin + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val projectId: JsonField, + private val promptId: JsonField, + private val promptVersion: JsonField, + private val additionalProperties: MutableMap, + ) { - @JsonProperty("position") @ExcludeMissing fun _position() = position + @JsonCreator + private constructor( + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("prompt_id") + @ExcludeMissing + promptId: JsonField = JsonMissing.of(), + @JsonProperty("prompt_version") + @ExcludeMissing + promptVersion: JsonField = JsonMissing.of(), + ) : this(projectId, promptId, promptVersion, mutableMapOf()) - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun projectId(): String? = projectId.getNullable("project_id") - fun validate(): Options = apply { - if (!validated) { - model() - params() - position() - validated = true - } - } + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptId(): String? = promptId.getNullable("prompt_id") - fun toBuilder() = Builder().from(this) + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptVersion(): String? = promptVersion.getNullable("prompt_version") - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * 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 [promptId]. + * + * Unlike [promptId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_id") @ExcludeMissing fun _promptId(): JsonField = promptId + + /** + * Returns the raw JSON value of [promptVersion]. + * + * Unlike [promptVersion], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("prompt_version") + @ExcludeMissing + fun _promptVersion(): JsonField = promptVersion - return other is Options && - this.model == other.model && - this.params == other.params && - this.position == other.position && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - model, - params, - position, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Options{model=$model, params=$params, position=$position, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [Origin]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Origin]. */ + class Builder internal constructor() { - private var model: JsonField = JsonMissing.of() - private var params: JsonField = JsonMissing.of() - private var position: JsonField = JsonMissing.of() + private var projectId: JsonField = JsonMissing.of() + private var promptId: JsonField = JsonMissing.of() + private var promptVersion: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() - internal fun from(options: Options) = apply { - this.model = options.model - this.params = options.params - this.position = options.position - additionalProperties(options.additionalProperties) + internal fun from(origin: Origin) = apply { + projectId = origin.projectId + promptId = origin.promptId + promptVersion = origin.promptVersion + additionalProperties = origin.additionalProperties.toMutableMap() } - fun model(model: String) = model(JsonField.of(model)) + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - @JsonProperty("model") - @ExcludeMissing - fun model(model: JsonField) = apply { this.model = model } + /** + * 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 params(params: Params) = params(JsonField.of(params)) + fun promptId(promptId: String) = promptId(JsonField.of(promptId)) - @JsonProperty("params") - @ExcludeMissing - fun params(params: JsonField) = apply { this.params = params } + /** + * Sets [Builder.promptId] to an arbitrary JSON value. + * + * You should usually call [Builder.promptId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptId(promptId: JsonField) = apply { this.promptId = promptId } - fun position(position: String) = position(JsonField.of(position)) + fun promptVersion(promptVersion: String) = promptVersion(JsonField.of(promptVersion)) - @JsonProperty("position") - @ExcludeMissing - fun position(position: JsonField) = apply { this.position = position } + /** + * Sets [Builder.promptVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.promptVersion] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptVersion(promptVersion: JsonField) = apply { + this.promptVersion = promptVersion + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Options = - Options( - model, - params, - position, - additionalProperties.toUnmodifiable(), - ) - } - - @JsonDeserialize(using = Params.Deserializer::class) - @JsonSerialize(using = Params.Serializer::class) - class Params - private constructor( - private val openaiModelParams: OpenAIModelParams? = null, - private val anthropicModelParams: AnthropicModelParams? = null, - private val googleModelParams: GoogleModelParams? = null, - private val windowAiModelParams: WindowAiModelParams? = null, - private val jsCompletionParams: JsCompletionParams? = null, - private val _json: JsonValue? = null, - ) { - - private var validated: Boolean = false - - fun openaiModelParams(): OpenAIModelParams? = openaiModelParams - - fun anthropicModelParams(): AnthropicModelParams? = anthropicModelParams - - fun googleModelParams(): GoogleModelParams? = googleModelParams - - fun windowAiModelParams(): WindowAiModelParams? = windowAiModelParams - - fun jsCompletionParams(): JsCompletionParams? = jsCompletionParams - - fun isOpenAIModelParams(): Boolean = openaiModelParams != null - - fun isAnthropicModelParams(): Boolean = anthropicModelParams != null - - fun isGoogleModelParams(): Boolean = googleModelParams != null - - fun isWindowAiModelParams(): Boolean = windowAiModelParams != null - - fun isJsCompletionParams(): Boolean = jsCompletionParams != null - - fun asOpenAIModelParams(): OpenAIModelParams = - openaiModelParams.getOrThrow("openaiModelParams") - - fun asAnthropicModelParams(): AnthropicModelParams = - anthropicModelParams.getOrThrow("anthropicModelParams") - - fun asGoogleModelParams(): GoogleModelParams = - googleModelParams.getOrThrow("googleModelParams") - - fun asWindowAiModelParams(): WindowAiModelParams = - windowAiModelParams.getOrThrow("windowAiModelParams") - - fun asJsCompletionParams(): JsCompletionParams = - jsCompletionParams.getOrThrow("jsCompletionParams") - - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { - openaiModelParams != null -> visitor.visitOpenAIModelParams(openaiModelParams) - anthropicModelParams != null -> - visitor.visitAnthropicModelParams(anthropicModelParams) - googleModelParams != null -> visitor.visitGoogleModelParams(googleModelParams) - windowAiModelParams != null -> - visitor.visitWindowAiModelParams(windowAiModelParams) - jsCompletionParams != null -> - visitor.visitJsCompletionParams(jsCompletionParams) - else -> visitor.unknown(_json) - } - } - - fun validate(): Params = apply { - if (!validated) { - if ( - openaiModelParams == null && - anthropicModelParams == null && - googleModelParams == null && - windowAiModelParams == null && - jsCompletionParams == null - ) { - throw BraintrustInvalidDataException("Unknown Params: $_json") - } - openaiModelParams?.validate() - anthropicModelParams?.validate() - googleModelParams?.validate() - windowAiModelParams?.validate() - jsCompletionParams?.validate() - validated = true - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Params && - this.openaiModelParams == other.openaiModelParams && - this.anthropicModelParams == other.anthropicModelParams && - this.googleModelParams == other.googleModelParams && - this.windowAiModelParams == other.windowAiModelParams && - this.jsCompletionParams == other.jsCompletionParams - } - - override fun hashCode(): Int { - return Objects.hash( - openaiModelParams, - anthropicModelParams, - googleModelParams, - windowAiModelParams, - jsCompletionParams, - ) - } - - override fun toString(): String { - return when { - openaiModelParams != null -> "Params{openaiModelParams=$openaiModelParams}" - anthropicModelParams != null -> - "Params{anthropicModelParams=$anthropicModelParams}" - googleModelParams != null -> "Params{googleModelParams=$googleModelParams}" - windowAiModelParams != null -> - "Params{windowAiModelParams=$windowAiModelParams}" - jsCompletionParams != null -> "Params{jsCompletionParams=$jsCompletionParams}" - _json != null -> "Params{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Params") - } - } - - companion object { - - fun ofOpenAIModelParams(openaiModelParams: OpenAIModelParams) = - Params(openaiModelParams = openaiModelParams) - - fun ofAnthropicModelParams(anthropicModelParams: AnthropicModelParams) = - Params(anthropicModelParams = anthropicModelParams) - - fun ofGoogleModelParams(googleModelParams: GoogleModelParams) = - Params(googleModelParams = googleModelParams) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun ofWindowAiModelParams(windowAiModelParams: WindowAiModelParams) = - Params(windowAiModelParams = windowAiModelParams) - - fun ofJsCompletionParams(jsCompletionParams: JsCompletionParams) = - Params(jsCompletionParams = jsCompletionParams) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) } - interface Visitor { - - fun visitOpenAIModelParams(openaiModelParams: OpenAIModelParams): T - - fun visitAnthropicModelParams(anthropicModelParams: AnthropicModelParams): T - - fun visitGoogleModelParams(googleModelParams: GoogleModelParams): T - - fun visitWindowAiModelParams(windowAiModelParams: WindowAiModelParams): T + /** + * Returns an immutable instance of [Origin]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Origin = + Origin(projectId, promptId, promptVersion, additionalProperties.toMutableMap()) + } - fun visitJsCompletionParams(jsCompletionParams: JsCompletionParams): T + private var validated: Boolean = false - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Params: $json") - } + fun validate(): Origin = apply { + if (validated) { + return@apply } - class Deserializer : BaseDeserializer(Params::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Params { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Params(openaiModelParams = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Params(anthropicModelParams = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Params(googleModelParams = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Params(windowAiModelParams = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Params(jsCompletionParams = it, _json = json) - } + projectId() + promptId() + promptVersion() + validated = true + } - return Params(_json = json) - } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - class Serializer : BaseSerializer(Params::class) { + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (projectId.asKnown() == null) 0 else 1) + + (if (promptId.asKnown() == null) 0 else 1) + + (if (promptVersion.asKnown() == null) 0 else 1) - override fun serialize( - value: Params, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.openaiModelParams != null -> - generator.writeObject(value.openaiModelParams) - value.anthropicModelParams != null -> - generator.writeObject(value.anthropicModelParams) - value.googleModelParams != null -> - generator.writeObject(value.googleModelParams) - value.windowAiModelParams != null -> - generator.writeObject(value.windowAiModelParams) - value.jsCompletionParams != null -> - generator.writeObject(value.jsCompletionParams) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Params") - } - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - @JsonDeserialize(builder = OpenAIModelParams.Builder::class) - @NoAutoDetect - class OpenAIModelParams - private constructor( - private val useCache: JsonField, - private val temperature: JsonField, - private val topP: JsonField, - private val maxTokens: JsonField, - private val frequencyPenalty: JsonField, - private val presencePenalty: JsonField, - private val responseFormat: JsonField, - private val toolChoice: JsonField, - private val functionCall: JsonField, - private val n: JsonField, - private val stop: JsonField>, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun useCache(): Boolean? = useCache.getNullable("use_cache") - - fun temperature(): Double? = temperature.getNullable("temperature") - - fun topP(): Double? = topP.getNullable("top_p") - - fun maxTokens(): Double? = maxTokens.getNullable("max_tokens") - - fun frequencyPenalty(): Double? = frequencyPenalty.getNullable("frequency_penalty") - - fun presencePenalty(): Double? = presencePenalty.getNullable("presence_penalty") - - fun responseFormat(): ResponseFormat? = - responseFormat.getNullable("response_format") - - fun toolChoice(): ToolChoice? = toolChoice.getNullable("tool_choice") - - fun functionCall(): FunctionCall? = functionCall.getNullable("function_call") - - fun n(): Double? = n.getNullable("n") - - fun stop(): List? = stop.getNullable("stop") - - @JsonProperty("use_cache") @ExcludeMissing fun _useCache() = useCache - - @JsonProperty("temperature") @ExcludeMissing fun _temperature() = temperature + return other is Origin && + projectId == other.projectId && + promptId == other.promptId && + promptVersion == other.promptVersion && + additionalProperties == other.additionalProperties + } - @JsonProperty("top_p") @ExcludeMissing fun _topP() = topP + private val hashCode: Int by lazy { + Objects.hash(projectId, promptId, promptVersion, additionalProperties) + } - @JsonProperty("max_tokens") @ExcludeMissing fun _maxTokens() = maxTokens + override fun hashCode(): Int = hashCode - @JsonProperty("frequency_penalty") - @ExcludeMissing - fun _frequencyPenalty() = frequencyPenalty + override fun toString() = + "Origin{projectId=$projectId, promptId=$promptId, promptVersion=$promptVersion, additionalProperties=$additionalProperties}" + } - @JsonProperty("presence_penalty") - @ExcludeMissing - fun _presencePenalty() = presencePenalty + class Parser + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val choiceScores: JsonField, + private val type: JsonField, + private val useCot: JsonField, + private val additionalProperties: MutableMap, + ) { - @JsonProperty("response_format") - @ExcludeMissing - fun _responseFormat() = responseFormat + @JsonCreator + private constructor( + @JsonProperty("choice_scores") + @ExcludeMissing + choiceScores: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("use_cot") @ExcludeMissing useCot: JsonField = JsonMissing.of(), + ) : this(choiceScores, type, useCot, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 choiceScores(): ChoiceScores = choiceScores.getRequired("choice_scores") - @JsonProperty("tool_choice") @ExcludeMissing fun _toolChoice() = toolChoice + /** + * @throws BraintrustInvalidDataException 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") - @JsonProperty("function_call") @ExcludeMissing fun _functionCall() = functionCall + /** + * @throws BraintrustInvalidDataException 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 useCot(): Boolean = useCot.getRequired("use_cot") - @JsonProperty("n") @ExcludeMissing fun _n() = n + /** + * Returns the raw JSON value of [choiceScores]. + * + * Unlike [choiceScores], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("choice_scores") + @ExcludeMissing + fun _choiceScores(): JsonField = choiceScores + + /** + * 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 [useCot]. + * + * Unlike [useCot], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("use_cot") @ExcludeMissing fun _useCot(): JsonField = useCot - @JsonProperty("stop") @ExcludeMissing fun _stop() = stop + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): OpenAIModelParams = apply { - if (!validated) { - useCache() - temperature() - topP() - maxTokens() - frequencyPenalty() - presencePenalty() - responseFormat()?.validate() - toolChoice() - functionCall() - n() - stop() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is OpenAIModelParams && - this.useCache == other.useCache && - this.temperature == other.temperature && - this.topP == other.topP && - this.maxTokens == other.maxTokens && - this.frequencyPenalty == other.frequencyPenalty && - this.presencePenalty == other.presencePenalty && - this.responseFormat == other.responseFormat && - this.toolChoice == other.toolChoice && - this.functionCall == other.functionCall && - this.n == other.n && - this.stop == other.stop && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - useCache, - temperature, - topP, - maxTokens, - frequencyPenalty, - presencePenalty, - responseFormat, - toolChoice, - functionCall, - n, - stop, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "OpenAIModelParams{useCache=$useCache, temperature=$temperature, topP=$topP, maxTokens=$maxTokens, frequencyPenalty=$frequencyPenalty, presencePenalty=$presencePenalty, responseFormat=$responseFormat, toolChoice=$toolChoice, functionCall=$functionCall, n=$n, stop=$stop, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var useCache: JsonField = JsonMissing.of() - private var temperature: JsonField = JsonMissing.of() - private var topP: JsonField = JsonMissing.of() - private var maxTokens: JsonField = JsonMissing.of() - private var frequencyPenalty: JsonField = JsonMissing.of() - private var presencePenalty: JsonField = JsonMissing.of() - private var responseFormat: JsonField = JsonMissing.of() - private var toolChoice: JsonField = JsonMissing.of() - private var functionCall: JsonField = JsonMissing.of() - private var n: JsonField = JsonMissing.of() - private var stop: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(openaiModelParams: OpenAIModelParams) = apply { - this.useCache = openaiModelParams.useCache - this.temperature = openaiModelParams.temperature - this.topP = openaiModelParams.topP - this.maxTokens = openaiModelParams.maxTokens - this.frequencyPenalty = openaiModelParams.frequencyPenalty - this.presencePenalty = openaiModelParams.presencePenalty - this.responseFormat = openaiModelParams.responseFormat - this.toolChoice = openaiModelParams.toolChoice - this.functionCall = openaiModelParams.functionCall - this.n = openaiModelParams.n - this.stop = openaiModelParams.stop - additionalProperties(openaiModelParams.additionalProperties) - } - - fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) - - @JsonProperty("use_cache") - @ExcludeMissing - fun useCache(useCache: JsonField) = apply { this.useCache = useCache } - - fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) - - @JsonProperty("temperature") - @ExcludeMissing - fun temperature(temperature: JsonField) = apply { - this.temperature = temperature - } - - fun topP(topP: Double) = topP(JsonField.of(topP)) - - @JsonProperty("top_p") - @ExcludeMissing - fun topP(topP: JsonField) = apply { this.topP = topP } - - fun maxTokens(maxTokens: Double) = maxTokens(JsonField.of(maxTokens)) - - @JsonProperty("max_tokens") - @ExcludeMissing - fun maxTokens(maxTokens: JsonField) = apply { - this.maxTokens = maxTokens - } - - fun frequencyPenalty(frequencyPenalty: Double) = - frequencyPenalty(JsonField.of(frequencyPenalty)) - - @JsonProperty("frequency_penalty") - @ExcludeMissing - fun frequencyPenalty(frequencyPenalty: JsonField) = apply { - this.frequencyPenalty = frequencyPenalty - } - - fun presencePenalty(presencePenalty: Double) = - presencePenalty(JsonField.of(presencePenalty)) - - @JsonProperty("presence_penalty") - @ExcludeMissing - fun presencePenalty(presencePenalty: JsonField) = apply { - this.presencePenalty = presencePenalty - } - - fun responseFormat(responseFormat: ResponseFormat) = - responseFormat(JsonField.of(responseFormat)) - - @JsonProperty("response_format") - @ExcludeMissing - fun responseFormat(responseFormat: JsonField) = apply { - this.responseFormat = responseFormat - } - - fun toolChoice(toolChoice: ToolChoice) = toolChoice(JsonField.of(toolChoice)) - - @JsonProperty("tool_choice") - @ExcludeMissing - fun toolChoice(toolChoice: JsonField) = apply { - this.toolChoice = toolChoice - } - - fun functionCall(functionCall: FunctionCall) = - functionCall(JsonField.of(functionCall)) - - @JsonProperty("function_call") - @ExcludeMissing - fun functionCall(functionCall: JsonField) = apply { - this.functionCall = functionCall - } - - fun n(n: Double) = n(JsonField.of(n)) - - @JsonProperty("n") - @ExcludeMissing - fun n(n: JsonField) = apply { this.n = n } - - fun stop(stop: List) = stop(JsonField.of(stop)) - - @JsonProperty("stop") - @ExcludeMissing - fun stop(stop: JsonField>) = apply { this.stop = stop } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): OpenAIModelParams = - OpenAIModelParams( - useCache, - temperature, - topP, - maxTokens, - frequencyPenalty, - presencePenalty, - responseFormat, - toolChoice, - functionCall, - n, - stop.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), - ) - } - - @JsonDeserialize(using = FunctionCall.Deserializer::class) - @JsonSerialize(using = FunctionCall.Serializer::class) - class FunctionCall - private constructor( - private val auto: Auto? = null, - private val none: None? = null, - private val function: Function? = null, - private val _json: JsonValue? = null, - ) { - - private var validated: Boolean = false - - fun auto(): Auto? = auto - - fun none(): None? = none - - fun function(): Function? = function - - fun isAuto(): Boolean = auto != null - - fun isNone(): Boolean = none != null - - fun isFunction(): Boolean = function != null - - fun asAuto(): Auto = auto.getOrThrow("auto") - - fun asNone(): None = none.getOrThrow("none") - - fun asFunction(): Function = function.getOrThrow("function") - - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { - auto != null -> visitor.visitAuto(auto) - none != null -> visitor.visitNone(none) - function != null -> visitor.visitFunction(function) - else -> visitor.unknown(_json) - } - } - - fun validate(): FunctionCall = apply { - if (!validated) { - if (auto == null && none == null && function == null) { - throw BraintrustInvalidDataException("Unknown FunctionCall: $_json") - } - function?.validate() - validated = true - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is FunctionCall && - this.auto == other.auto && - this.none == other.none && - this.function == other.function - } - - override fun hashCode(): Int { - return Objects.hash( - auto, - none, - function, - ) - } - - override fun toString(): String { - return when { - auto != null -> "FunctionCall{auto=$auto}" - none != null -> "FunctionCall{none=$none}" - function != null -> "FunctionCall{function=$function}" - _json != null -> "FunctionCall{_unknown=$_json}" - else -> throw IllegalStateException("Invalid FunctionCall") - } - } - - companion object { - - fun ofAuto(auto: Auto) = FunctionCall(auto = auto) - - fun ofNone(none: None) = FunctionCall(none = none) - - fun ofFunction(function: Function) = FunctionCall(function = function) - } - - interface Visitor { - - fun visitAuto(auto: Auto): T - - fun visitNone(none: None): T - - fun visitFunction(function: Function): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown FunctionCall: $json") - } - } - - class Deserializer : BaseDeserializer(FunctionCall::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): FunctionCall { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return FunctionCall(auto = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef())?.let { - return FunctionCall(none = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return FunctionCall(function = it, _json = json) - } - - return FunctionCall(_json = json) - } - } - - class Serializer : BaseSerializer(FunctionCall::class) { - - override fun serialize( - value: FunctionCall, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.none != null -> generator.writeObject(value.none) - value.function != null -> generator.writeObject(value.function) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid FunctionCall") - } - } - } - - class Auto - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Auto && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val AUTO = Auto(JsonField.of("auto")) - - fun of(value: String) = Auto(JsonField.of(value)) - } - - enum class Known { - AUTO, - } - - enum class Value { - AUTO, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - AUTO -> Value.AUTO - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - AUTO -> Known.AUTO - else -> throw BraintrustInvalidDataException("Unknown Auto: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - - class None - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is None && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val NONE = None(JsonField.of("none")) - - fun of(value: String) = None(JsonField.of(value)) - } - - enum class Known { - NONE, - } - - enum class Value { - NONE, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - NONE -> Value.NONE - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - NONE -> Known.NONE - else -> throw BraintrustInvalidDataException("Unknown None: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect - class Function - private constructor( - private val name: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun name(): String = name.getRequired("name") - - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - name() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Function && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(name, additionalProperties) - } - return hashCode - } - - override fun toString() = - "Function{name=$name, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var name: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = - mutableMapOf() - - internal fun from(function: Function) = apply { - this.name = function.name - additionalProperties(function.additionalProperties) - } - - fun name(name: String) = name(JsonField.of(name)) - - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun build(): Function = - Function(name, additionalProperties.toUnmodifiable()) - } - } - } - - @JsonDeserialize(builder = ResponseFormat.Builder::class) - @NoAutoDetect - class ResponseFormat - private constructor( - private val type: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun type(): Type = type.getRequired("type") - - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ResponseFormat = apply { - if (!validated) { - type() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ResponseFormat && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(type, additionalProperties) - } - return hashCode - } - - override fun toString() = - "ResponseFormat{type=$type, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = - mutableMapOf() - - internal fun from(responseFormat: ResponseFormat) = apply { - this.type = responseFormat.type - additionalProperties(responseFormat.additionalProperties) - } - - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun build(): ResponseFormat = - ResponseFormat(type, additionalProperties.toUnmodifiable()) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val JSON_OBJECT = Type(JsonField.of("json_object")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - JSON_OBJECT, - } - - enum class Value { - JSON_OBJECT, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - JSON_OBJECT -> Value.JSON_OBJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - JSON_OBJECT -> Known.JSON_OBJECT - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } - } - - @JsonDeserialize(builder = AnthropicModelParams.Builder::class) - @NoAutoDetect - class AnthropicModelParams - private constructor( - private val useCache: JsonField, - private val maxTokens: JsonField, - private val temperature: JsonField, - private val topP: JsonField, - private val topK: JsonField, - private val stopSequences: JsonField>, - private val maxTokensToSample: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun useCache(): Boolean? = useCache.getNullable("use_cache") - - fun maxTokens(): Double = maxTokens.getRequired("max_tokens") - - fun temperature(): Double = temperature.getRequired("temperature") - - fun topP(): Double? = topP.getNullable("top_p") - - fun topK(): Double? = topK.getNullable("top_k") - - fun stopSequences(): List? = stopSequences.getNullable("stop_sequences") - - /** This is a legacy parameter that should not be used. */ - fun maxTokensToSample(): Double? = - maxTokensToSample.getNullable("max_tokens_to_sample") - - @JsonProperty("use_cache") @ExcludeMissing fun _useCache() = useCache - - @JsonProperty("max_tokens") @ExcludeMissing fun _maxTokens() = maxTokens - - @JsonProperty("temperature") @ExcludeMissing fun _temperature() = temperature - - @JsonProperty("top_p") @ExcludeMissing fun _topP() = topP - - @JsonProperty("top_k") @ExcludeMissing fun _topK() = topK - - @JsonProperty("stop_sequences") @ExcludeMissing fun _stopSequences() = stopSequences - - /** This is a legacy parameter that should not be used. */ - @JsonProperty("max_tokens_to_sample") - @ExcludeMissing - fun _maxTokensToSample() = maxTokensToSample - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): AnthropicModelParams = apply { - if (!validated) { - useCache() - maxTokens() - temperature() - topP() - topK() - stopSequences() - maxTokensToSample() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AnthropicModelParams && - this.useCache == other.useCache && - this.maxTokens == other.maxTokens && - this.temperature == other.temperature && - this.topP == other.topP && - this.topK == other.topK && - this.stopSequences == other.stopSequences && - this.maxTokensToSample == other.maxTokensToSample && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - useCache, - maxTokens, - temperature, - topP, - topK, - stopSequences, - maxTokensToSample, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "AnthropicModelParams{useCache=$useCache, maxTokens=$maxTokens, temperature=$temperature, topP=$topP, topK=$topK, stopSequences=$stopSequences, maxTokensToSample=$maxTokensToSample, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var useCache: JsonField = JsonMissing.of() - private var maxTokens: JsonField = JsonMissing.of() - private var temperature: JsonField = JsonMissing.of() - private var topP: JsonField = JsonMissing.of() - private var topK: JsonField = JsonMissing.of() - private var stopSequences: JsonField> = JsonMissing.of() - private var maxTokensToSample: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(anthropicModelParams: AnthropicModelParams) = apply { - this.useCache = anthropicModelParams.useCache - this.maxTokens = anthropicModelParams.maxTokens - this.temperature = anthropicModelParams.temperature - this.topP = anthropicModelParams.topP - this.topK = anthropicModelParams.topK - this.stopSequences = anthropicModelParams.stopSequences - this.maxTokensToSample = anthropicModelParams.maxTokensToSample - additionalProperties(anthropicModelParams.additionalProperties) - } - - fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) - - @JsonProperty("use_cache") - @ExcludeMissing - fun useCache(useCache: JsonField) = apply { this.useCache = useCache } - - fun maxTokens(maxTokens: Double) = maxTokens(JsonField.of(maxTokens)) - - @JsonProperty("max_tokens") - @ExcludeMissing - fun maxTokens(maxTokens: JsonField) = apply { - this.maxTokens = maxTokens - } - - fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) - - @JsonProperty("temperature") - @ExcludeMissing - fun temperature(temperature: JsonField) = apply { - this.temperature = temperature - } - - fun topP(topP: Double) = topP(JsonField.of(topP)) - - @JsonProperty("top_p") - @ExcludeMissing - fun topP(topP: JsonField) = apply { this.topP = topP } - - fun topK(topK: Double) = topK(JsonField.of(topK)) - - @JsonProperty("top_k") - @ExcludeMissing - fun topK(topK: JsonField) = apply { this.topK = topK } - - fun stopSequences(stopSequences: List) = - stopSequences(JsonField.of(stopSequences)) - - @JsonProperty("stop_sequences") - @ExcludeMissing - fun stopSequences(stopSequences: JsonField>) = apply { - this.stopSequences = stopSequences - } - - /** This is a legacy parameter that should not be used. */ - fun maxTokensToSample(maxTokensToSample: Double) = - maxTokensToSample(JsonField.of(maxTokensToSample)) - - /** This is a legacy parameter that should not be used. */ - @JsonProperty("max_tokens_to_sample") - @ExcludeMissing - fun maxTokensToSample(maxTokensToSample: JsonField) = apply { - this.maxTokensToSample = maxTokensToSample - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): AnthropicModelParams = - AnthropicModelParams( - useCache, - maxTokens, - temperature, - topP, - topK, - stopSequences.map { it.toUnmodifiable() }, - maxTokensToSample, - additionalProperties.toUnmodifiable(), - ) - } - } - - @JsonDeserialize(builder = GoogleModelParams.Builder::class) - @NoAutoDetect - class GoogleModelParams - private constructor( - private val useCache: JsonField, - private val temperature: JsonField, - private val maxOutputTokens: JsonField, - private val topP: JsonField, - private val topK: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun useCache(): Boolean? = useCache.getNullable("use_cache") - - fun temperature(): Double? = temperature.getNullable("temperature") - - fun maxOutputTokens(): Double? = maxOutputTokens.getNullable("maxOutputTokens") - - fun topP(): Double? = topP.getNullable("topP") - - fun topK(): Double? = topK.getNullable("topK") - - @JsonProperty("use_cache") @ExcludeMissing fun _useCache() = useCache - - @JsonProperty("temperature") @ExcludeMissing fun _temperature() = temperature - - @JsonProperty("maxOutputTokens") - @ExcludeMissing - fun _maxOutputTokens() = maxOutputTokens - - @JsonProperty("topP") @ExcludeMissing fun _topP() = topP - - @JsonProperty("topK") @ExcludeMissing fun _topK() = topK - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): GoogleModelParams = apply { - if (!validated) { - useCache() - temperature() - maxOutputTokens() - topP() - topK() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GoogleModelParams && - this.useCache == other.useCache && - this.temperature == other.temperature && - this.maxOutputTokens == other.maxOutputTokens && - this.topP == other.topP && - this.topK == other.topK && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - useCache, - temperature, - maxOutputTokens, - topP, - topK, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "GoogleModelParams{useCache=$useCache, temperature=$temperature, maxOutputTokens=$maxOutputTokens, topP=$topP, topK=$topK, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var useCache: JsonField = JsonMissing.of() - private var temperature: JsonField = JsonMissing.of() - private var maxOutputTokens: JsonField = JsonMissing.of() - private var topP: JsonField = JsonMissing.of() - private var topK: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(googleModelParams: GoogleModelParams) = apply { - this.useCache = googleModelParams.useCache - this.temperature = googleModelParams.temperature - this.maxOutputTokens = googleModelParams.maxOutputTokens - this.topP = googleModelParams.topP - this.topK = googleModelParams.topK - additionalProperties(googleModelParams.additionalProperties) - } - - fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) - - @JsonProperty("use_cache") - @ExcludeMissing - fun useCache(useCache: JsonField) = apply { this.useCache = useCache } - - fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) - - @JsonProperty("temperature") - @ExcludeMissing - fun temperature(temperature: JsonField) = apply { - this.temperature = temperature - } - - fun maxOutputTokens(maxOutputTokens: Double) = - maxOutputTokens(JsonField.of(maxOutputTokens)) - - @JsonProperty("maxOutputTokens") - @ExcludeMissing - fun maxOutputTokens(maxOutputTokens: JsonField) = apply { - this.maxOutputTokens = maxOutputTokens - } - - fun topP(topP: Double) = topP(JsonField.of(topP)) - - @JsonProperty("topP") - @ExcludeMissing - fun topP(topP: JsonField) = apply { this.topP = topP } - - fun topK(topK: Double) = topK(JsonField.of(topK)) - - @JsonProperty("topK") - @ExcludeMissing - fun topK(topK: JsonField) = apply { this.topK = topK } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): GoogleModelParams = - GoogleModelParams( - useCache, - temperature, - maxOutputTokens, - topP, - topK, - additionalProperties.toUnmodifiable(), - ) - } - } - - @JsonDeserialize(builder = WindowAiModelParams.Builder::class) - @NoAutoDetect - class WindowAiModelParams - private constructor( - private val useCache: JsonField, - private val temperature: JsonField, - private val topK: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun useCache(): Boolean? = useCache.getNullable("use_cache") - - fun temperature(): Double? = temperature.getNullable("temperature") - - fun topK(): Double? = topK.getNullable("topK") - - @JsonProperty("use_cache") @ExcludeMissing fun _useCache() = useCache - - @JsonProperty("temperature") @ExcludeMissing fun _temperature() = temperature - - @JsonProperty("topK") @ExcludeMissing fun _topK() = topK - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): WindowAiModelParams = apply { - if (!validated) { - useCache() - temperature() - topK() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is WindowAiModelParams && - this.useCache == other.useCache && - this.temperature == other.temperature && - this.topK == other.topK && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - useCache, - temperature, - topK, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "WindowAiModelParams{useCache=$useCache, temperature=$temperature, topK=$topK, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var useCache: JsonField = JsonMissing.of() - private var temperature: JsonField = JsonMissing.of() - private var topK: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(windowAiModelParams: WindowAiModelParams) = apply { - this.useCache = windowAiModelParams.useCache - this.temperature = windowAiModelParams.temperature - this.topK = windowAiModelParams.topK - additionalProperties(windowAiModelParams.additionalProperties) - } - - fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) - - @JsonProperty("use_cache") - @ExcludeMissing - fun useCache(useCache: JsonField) = apply { this.useCache = useCache } - - fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) - - @JsonProperty("temperature") - @ExcludeMissing - fun temperature(temperature: JsonField) = apply { - this.temperature = temperature - } - - fun topK(topK: Double) = topK(JsonField.of(topK)) - - @JsonProperty("topK") - @ExcludeMissing - fun topK(topK: JsonField) = apply { this.topK = topK } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): WindowAiModelParams = - WindowAiModelParams( - useCache, - temperature, - topK, - additionalProperties.toUnmodifiable(), - ) - } - } - - @JsonDeserialize(builder = JsCompletionParams.Builder::class) - @NoAutoDetect - class JsCompletionParams - private constructor( - private val useCache: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun useCache(): Boolean? = useCache.getNullable("use_cache") - - @JsonProperty("use_cache") @ExcludeMissing fun _useCache() = useCache - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): JsCompletionParams = apply { - if (!validated) { - useCache() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is JsCompletionParams && - this.useCache == other.useCache && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(useCache, additionalProperties) - } - return hashCode - } - - override fun toString() = - "JsCompletionParams{useCache=$useCache, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var useCache: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(jsCompletionParams: JsCompletionParams) = apply { - this.useCache = jsCompletionParams.useCache - additionalProperties(jsCompletionParams.additionalProperties) - } - - fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) - - @JsonProperty("use_cache") - @ExcludeMissing - fun useCache(useCache: JsonField) = apply { this.useCache = useCache } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): JsCompletionParams = - JsCompletionParams(useCache, additionalProperties.toUnmodifiable()) - } - } - } - } - - @JsonDeserialize(builder = Origin.Builder::class) - @NoAutoDetect - class Origin - private constructor( - private val promptId: JsonField, - private val projectId: JsonField, - private val promptVersion: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun promptId(): String? = promptId.getNullable("prompt_id") - - fun projectId(): String? = projectId.getNullable("project_id") - - fun promptVersion(): String? = promptVersion.getNullable("prompt_version") - - @JsonProperty("prompt_id") @ExcludeMissing fun _promptId() = promptId - - @JsonProperty("project_id") @ExcludeMissing fun _projectId() = projectId - - @JsonProperty("prompt_version") @ExcludeMissing fun _promptVersion() = promptVersion - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Origin = apply { - if (!validated) { - promptId() - projectId() - promptVersion() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Origin && - this.promptId == other.promptId && - this.projectId == other.projectId && - this.promptVersion == other.promptVersion && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - promptId, - projectId, - promptVersion, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Origin{promptId=$promptId, projectId=$projectId, promptVersion=$promptVersion, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var promptId: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var promptVersion: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(origin: Origin) = apply { - this.promptId = origin.promptId - this.projectId = origin.projectId - this.promptVersion = origin.promptVersion - additionalProperties(origin.additionalProperties) - } - - fun promptId(promptId: String) = promptId(JsonField.of(promptId)) - - @JsonProperty("prompt_id") - @ExcludeMissing - fun promptId(promptId: JsonField) = apply { this.promptId = promptId } - - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - @JsonProperty("project_id") - @ExcludeMissing - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } - - fun promptVersion(promptVersion: String) = promptVersion(JsonField.of(promptVersion)) - - @JsonProperty("prompt_version") - @ExcludeMissing - fun promptVersion(promptVersion: JsonField) = apply { - this.promptVersion = promptVersion - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Origin = - Origin( - promptId, - projectId, - promptVersion, - additionalProperties.toUnmodifiable(), - ) - } - } - - @JsonDeserialize(builder = Parser.Builder::class) - @NoAutoDetect - class Parser - private constructor( - private val type: JsonField, - private val useCot: JsonField, - private val choiceScores: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun type(): Type = type.getRequired("type") - - fun useCot(): Boolean = useCot.getRequired("use_cot") - - fun choiceScores(): ChoiceScores = choiceScores.getRequired("choice_scores") - - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonProperty("use_cot") @ExcludeMissing fun _useCot() = useCot - - @JsonProperty("choice_scores") @ExcludeMissing fun _choiceScores() = choiceScores - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Parser = apply { - if (!validated) { - type() - useCot() - choiceScores().validate() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Parser && - this.type == other.type && - this.useCot == other.useCot && - this.choiceScores == other.choiceScores && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - useCot, - choiceScores, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Parser{type=$type, useCot=$useCot, choiceScores=$choiceScores, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Parser]. + * + * The following fields are required: + * ```kotlin + * .choiceScores() + * .type() + * .useCot() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Parser]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var useCot: JsonField = JsonMissing.of() - private var choiceScores: JsonField = JsonMissing.of() + private var choiceScores: JsonField? = null + private var type: JsonField? = null + private var useCot: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(parser: Parser) = apply { - this.type = parser.type - this.useCot = parser.useCot - this.choiceScores = parser.choiceScores - additionalProperties(parser.additionalProperties) + choiceScores = parser.choiceScores + type = parser.type + useCot = parser.useCot + additionalProperties = parser.additionalProperties.toMutableMap() + } + + fun choiceScores(choiceScores: ChoiceScores) = choiceScores(JsonField.of(choiceScores)) + + /** + * Sets [Builder.choiceScores] to an arbitrary JSON value. + * + * You should usually call [Builder.choiceScores] with a well-typed [ChoiceScores] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun choiceScores(choiceScores: JsonField) = apply { + this.choiceScores = choiceScores } fun type(type: Type) = type(JsonField.of(type)) - @JsonProperty("type") - @ExcludeMissing + /** + * 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 useCot(useCot: Boolean) = useCot(JsonField.of(useCot)) - @JsonProperty("use_cot") - @ExcludeMissing + /** + * Sets [Builder.useCot] to an arbitrary JSON value. + * + * You should usually call [Builder.useCot] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun useCot(useCot: JsonField) = apply { this.useCot = useCot } - fun choiceScores(choiceScores: ChoiceScores) = choiceScores(JsonField.of(choiceScores)) - - @JsonProperty("choice_scores") - @ExcludeMissing - fun choiceScores(choiceScores: JsonField) = apply { - this.choiceScores = choiceScores - } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Parser]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .choiceScores() + * .type() + * .useCot() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Parser = Parser( - type, - useCot, - choiceScores, - additionalProperties.toUnmodifiable(), + checkRequired("choiceScores", choiceScores), + checkRequired("type", type), + checkRequired("useCot", useCot), + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = ChoiceScores.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): Parser = apply { + if (validated) { + return@apply + } + + choiceScores().validate() + type().validate() + useCot() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (choiceScores.asKnown()?.validity() ?: 0) + + (type.asKnown()?.validity() ?: 0) + + (if (useCot.asKnown() == null) 0 else 1) + class ChoiceScores + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): ChoiceScores = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ChoiceScores && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "ChoiceScores{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [ChoiceScores]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ChoiceScores]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(choiceScores: ChoiceScores) = apply { - additionalProperties(choiceScores.additionalProperties) + additionalProperties = choiceScores.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2246,60 +776,203 @@ private constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): ChoiceScores = ChoiceScores(additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ChoiceScores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ChoiceScores = ChoiceScores(additionalProperties.toImmutable()) } - } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): ChoiceScores = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Type && this.value == other.value + return other is ChoiceScores && additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = "ChoiceScores{additionalProperties=$additionalProperties}" + } + + 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 { - val LLM_CLASSIFIER = Type(JsonField.of("llm_classifier")) + val LLM_CLASSIFIER = of("llm_classifier") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - LLM_CLASSIFIER, + LLM_CLASSIFIER } + /** + * 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 { LLM_CLASSIFIER, + /** 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) { LLM_CLASSIFIER -> Value.LLM_CLASSIFIER 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { LLM_CLASSIFIER -> Known.LLM_CLASSIFIER else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Parser && + choiceScores == other.choiceScores && + type == other.type && + useCot == other.useCot && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(choiceScores, type, useCot, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Parser{choiceScores=$choiceScores, type=$type, useCot=$useCot, additionalProperties=$additionalProperties}" } @JsonDeserialize(using = Prompt.Deserializer::class) @@ -2308,241 +981,281 @@ private constructor( private constructor( private val completion: Completion? = null, private val chat: Chat? = null, - private val nullableVariant: NullableVariant? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun completion(): Completion? = completion fun chat(): Chat? = chat - fun nullableVariant(): NullableVariant? = nullableVariant - fun isCompletion(): Boolean = completion != null fun isChat(): Boolean = chat != null - fun isNullableVariant(): Boolean = nullableVariant != null - fun asCompletion(): Completion = completion.getOrThrow("completion") fun asChat(): Chat = chat.getOrThrow("chat") - fun asNullableVariant(): NullableVariant = nullableVariant.getOrThrow("nullableVariant") - fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { completion != null -> visitor.visitCompletion(completion) chat != null -> visitor.visitChat(chat) - nullableVariant != null -> visitor.visitNullableVariant(nullableVariant) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Prompt = apply { - if (!validated) { - if (completion == null && chat == null && nullableVariant == null) { - throw BraintrustInvalidDataException("Unknown Prompt: $_json") - } - completion?.validate() - chat?.validate() - nullableVariant?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitCompletion(completion: Completion) { + completion.validate() + } + + override fun visitChat(chat: Chat) { + chat.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitCompletion(completion: Completion) = completion.validity() + + override fun visitChat(chat: Chat) = chat.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Prompt && - this.completion == other.completion && - this.chat == other.chat && - this.nullableVariant == other.nullableVariant + return other is Prompt && completion == other.completion && chat == other.chat } - override fun hashCode(): Int { - return Objects.hash( - completion, - chat, - nullableVariant, - ) - } + override fun hashCode(): Int = Objects.hash(completion, chat) - override fun toString(): String { - return when { + override fun toString(): String = + when { completion != null -> "Prompt{completion=$completion}" chat != null -> "Prompt{chat=$chat}" - nullableVariant != null -> "Prompt{nullableVariant=$nullableVariant}" _json != null -> "Prompt{_unknown=$_json}" else -> throw IllegalStateException("Invalid Prompt") } - } companion object { fun ofCompletion(completion: Completion) = Prompt(completion = completion) fun ofChat(chat: Chat) = Prompt(chat = chat) - - fun ofNullableVariant(nullableVariant: NullableVariant) = - Prompt(nullableVariant = nullableVariant) } + /** An interface that defines how to map each variant of [Prompt] to a value of type [T]. */ interface Visitor { fun visitCompletion(completion: Completion): T fun visitChat(chat: Chat): T - fun visitNullableVariant(nullableVariant: NullableVariant): T - + /** + * Maps an unknown variant of [Prompt] to a value of type [T]. + * + * An instance of [Prompt] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Prompt: $json") } } - class Deserializer : BaseDeserializer(Prompt::class) { + internal class Deserializer : BaseDeserializer(Prompt::class) { override fun ObjectCodec.deserialize(node: JsonNode): Prompt { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Prompt(completion = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Prompt(chat = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Prompt(nullableVariant = it, _json = json) - } - return Prompt(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Prompt(completion = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Prompt(chat = 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 -> Prompt(_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() + } } } - class Serializer : BaseSerializer(Prompt::class) { + internal class Serializer : BaseSerializer(Prompt::class) { override fun serialize( value: Prompt, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.completion != null -> generator.writeObject(value.completion) value.chat != null -> generator.writeObject(value.chat) - value.nullableVariant != null -> generator.writeObject(value.nullableVariant) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Prompt") } } } - @JsonDeserialize(builder = Completion.Builder::class) - @NoAutoDetect class Completion + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val type: JsonField, private val content: JsonField, - private val additionalProperties: Map, + private val type: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(content, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 content(): String = content.getRequired("content") + /** + * @throws BraintrustInvalidDataException 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") - fun content(): String = content.getRequired("content") + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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 - @JsonProperty("content") @ExcludeMissing fun _content() = content + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Completion = apply { - if (!validated) { - type() - content() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Completion && - this.type == other.type && - this.content == other.content && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - content, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Completion{type=$type, content=$content, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Completion]. + * + * The following fields are required: + * ```kotlin + * .content() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Completion]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var content: JsonField = JsonMissing.of() + private var content: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(completion: Completion) = apply { - this.type = completion.type - this.content = completion.content - additionalProperties(completion.additionalProperties) + content = completion.content + type = completion.type + additionalProperties = completion.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun content(content: String) = content(JsonField.of(content)) - @JsonProperty("content") - @ExcludeMissing + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun content(content: JsonField) = apply { this.content = content } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2550,182 +1263,384 @@ private constructor( 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 [Completion]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .content() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Completion = Completion( - type, - content, - additionalProperties.toUnmodifiable(), + checkRequired("content", content), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false + + fun validate(): Completion = apply { + if (validated) { + return@apply + } + + content() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (content.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { + + val COMPLETION = of("completion") + + fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + COMPLETION + } + + /** + * 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 { + COMPLETION, + /** + * 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) { + COMPLETION -> Value.COMPLETION + 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + COMPLETION -> Known.COMPLETION + else -> throw BraintrustInvalidDataException("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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 && this.value == other.value + return other is Type && value == other.value } override fun hashCode() = value.hashCode() override fun toString() = value.toString() + } - companion object { - - val COMPLETION = Type(JsonField.of("completion")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - COMPLETION, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - enum class Value { - COMPLETION, - _UNKNOWN, - } + return other is Completion && + content == other.content && + type == other.type && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - COMPLETION -> Value.COMPLETION - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { Objects.hash(content, type, additionalProperties) } - fun known(): Known = - when (this) { - COMPLETION -> Known.COMPLETION - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "Completion{content=$content, type=$type, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Chat.Builder::class) - @NoAutoDetect class Chat + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val type: JsonField, private val messages: JsonField>, + private val type: JsonField, private val tools: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("messages") + @ExcludeMissing + messages: JsonField> = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("tools") @ExcludeMissing tools: JsonField = JsonMissing.of(), + ) : this(messages, type, tools, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 messages(): List = messages.getRequired("messages") + /** + * @throws BraintrustInvalidDataException 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") - fun messages(): List = messages.getRequired("messages") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ fun tools(): String? = tools.getNullable("tools") - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonProperty("messages") @ExcludeMissing fun _messages() = messages + /** + * Returns the raw JSON value of [messages]. + * + * Unlike [messages], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("messages") + @ExcludeMissing + fun _messages(): JsonField> = messages + + /** + * 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 [tools]. + * + * Unlike [tools], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tools") @ExcludeMissing fun _tools(): JsonField = tools - @JsonProperty("tools") @ExcludeMissing fun _tools() = tools + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Chat = apply { - if (!validated) { - type() - messages() - tools() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Chat && - this.type == other.type && - this.messages == other.messages && - this.tools == other.tools && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - messages, - tools, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Chat{type=$type, messages=$messages, tools=$tools, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Chat]. + * + * The following fields are required: + * ```kotlin + * .messages() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Chat]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var messages: JsonField> = JsonMissing.of() + private var messages: JsonField>? = null + private var type: JsonField? = null private var tools: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(chat: Chat) = apply { - this.type = chat.type - this.messages = chat.messages - this.tools = chat.tools - additionalProperties(chat.additionalProperties) + messages = chat.messages.map { it.toMutableList() } + type = chat.type + tools = chat.tools + additionalProperties = chat.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun messages(messages: List) = messages(JsonField.of(messages)) - @JsonProperty("messages") - @ExcludeMissing + /** + * Sets [Builder.messages] to an arbitrary JSON value. + * + * You should usually call [Builder.messages] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ fun messages(messages: JsonField>) = apply { - this.messages = messages + this.messages = messages.map { it.toMutableList() } + } + + /** + * Adds a single [Message] to [messages]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMessage(message: Message) = apply { + messages = + (messages ?: JsonField.of(mutableListOf())).also { + checkKnown("messages", it).add(message) + } } + /** Alias for calling [addMessage] with `Message.ofSystem(system)`. */ + fun addMessage(system: Message.System) = addMessage(Message.ofSystem(system)) + + /** Alias for calling [addMessage] with `Message.ofUser(user)`. */ + fun addMessage(user: Message.User) = addMessage(Message.ofUser(user)) + + /** Alias for calling [addMessage] with `Message.ofAssistant(assistant)`. */ + fun addMessage(assistant: Message.Assistant) = + addMessage(Message.ofAssistant(assistant)) + + /** Alias for calling [addMessage] with `Message.ofTool(tool)`. */ + fun addMessage(tool: Message.Tool) = addMessage(Message.ofTool(tool)) + + /** Alias for calling [addMessage] with `Message.ofFunction(function)`. */ + fun addMessage(function: Message.Function) = + addMessage(Message.ofFunction(function)) + + /** Alias for calling [addMessage] with `Message.ofFallback(fallback)`. */ + fun addMessage(fallback: Message.Fallback) = + addMessage(Message.ofFallback(fallback)) + + 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 tools(tools: String) = tools(JsonField.of(tools)) - @JsonProperty("tools") - @ExcludeMissing + /** + * Sets [Builder.tools] to an arbitrary JSON value. + * + * You should usually call [Builder.tools] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun tools(tools: JsonField) = apply { this.tools = tools } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -2733,15 +1648,68 @@ private constructor( 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 [Chat]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .messages() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Chat = Chat( - type, - messages.map { it.toUnmodifiable() }, + checkRequired("messages", messages).map { it.toImmutable() }, + checkRequired("type", type), tools, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): Chat = apply { + if (validated) { + return@apply + } + + messages().forEach { it.validate() } + type().validate() + tools() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (messages.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (type.asKnown()?.validity() ?: 0) + + (if (tools.asKnown() == null) 0 else 1) + @JsonDeserialize(using = Message.Deserializer::class) @JsonSerialize(using = Message.Serializer::class) class Message @@ -2755,8 +1723,6 @@ private constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun system(): System? = system fun user(): User? = user @@ -2795,8 +1761,8 @@ private constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { system != null -> visitor.visitSystem(system) user != null -> visitor.visitUser(user) assistant != null -> visitor.visitAssistant(assistant) @@ -2805,57 +1771,96 @@ private constructor( fallback != null -> visitor.visitFallback(fallback) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Message = apply { - if (!validated) { - if ( - system == null && - user == null && - assistant == null && - tool == null && - function == null && - fallback == null - ) { - throw BraintrustInvalidDataException("Unknown Message: $_json") - } - system?.validate() - user?.validate() - assistant?.validate() - tool?.validate() - function?.validate() - fallback?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitSystem(system: System) { + system.validate() + } + + override fun visitUser(user: User) { + user.validate() + } + + override fun visitAssistant(assistant: Assistant) { + assistant.validate() + } + + override fun visitTool(tool: Tool) { + tool.validate() + } + + override fun visitFunction(function: Function) { + function.validate() + } + + override fun visitFallback(fallback: Fallback) { + fallback.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitSystem(system: System) = system.validity() + + override fun visitUser(user: User) = user.validity() + + override fun visitAssistant(assistant: Assistant) = assistant.validity() + + override fun visitTool(tool: Tool) = tool.validity() + + override fun visitFunction(function: Function) = function.validity() + + override fun visitFallback(fallback: Fallback) = fallback.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is Message && - this.system == other.system && - this.user == other.user && - this.assistant == other.assistant && - this.tool == other.tool && - this.function == other.function && - this.fallback == other.fallback + system == other.system && + user == other.user && + assistant == other.assistant && + tool == other.tool && + function == other.function && + fallback == other.fallback } - override fun hashCode(): Int { - return Objects.hash( - system, - user, - assistant, - tool, - function, - fallback, - ) - } + override fun hashCode(): Int = + Objects.hash(system, user, assistant, tool, function, fallback) - override fun toString(): String { - return when { + override fun toString(): String = + when { system != null -> "Message{system=$system}" user != null -> "Message{user=$user}" assistant != null -> "Message{assistant=$assistant}" @@ -2865,7 +1870,6 @@ private constructor( _json != null -> "Message{_unknown=$_json}" else -> throw IllegalStateException("Invalid Message") } - } companion object { @@ -2882,6 +1886,10 @@ private constructor( fun ofFallback(fallback: Fallback) = Message(fallback = fallback) } + /** + * An interface that defines how to map each variant of [Message] to a value of type + * [T]. + */ interface Visitor { fun visitSystem(system: System): T @@ -2896,50 +1904,70 @@ private constructor( fun visitFallback(fallback: Fallback): T + /** + * Maps an unknown variant of [Message] to a value of type [T]. + * + * An instance of [Message] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Message: $json") } } - class Deserializer : BaseDeserializer(Message::class) { + internal class Deserializer : BaseDeserializer(Message::class) { override fun ObjectCodec.deserialize(node: JsonNode): Message { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(system = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(user = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(assistant = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(tool = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(function = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return Message(fallback = it, _json = json) - } - return Message(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Message(system = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(user = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(assistant = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(tool = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(function = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Message(fallback = 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 -> Message(_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() + } } } - class Serializer : BaseSerializer(Message::class) { + internal class Serializer : BaseSerializer(Message::class) { override fun serialize( value: Message, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.system != null -> generator.writeObject(value.system) @@ -2954,501 +1982,897 @@ private constructor( } } - @JsonDeserialize(builder = System.Builder::class) - @NoAutoDetect class System + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val content: JsonField, private val role: JsonField, + private val content: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("role") + @ExcludeMissing + role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + ) : this(role, content, name, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun content(): String? = content.getNullable("content") - fun role(): Role = role.getRequired("role") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") - @JsonProperty("content") @ExcludeMissing fun _content() = content + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("content") + @ExcludeMissing + fun _content(): JsonField = content - @JsonProperty("role") @ExcludeMissing fun _role() = role + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): System = apply { - if (!validated) { - content() - role() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is System && - this.content == other.content && - this.role == other.role && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - role, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "System{content=$content, role=$role, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [System]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [System]. */ + class Builder internal constructor() { + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(system: System) = apply { - this.content = system.content - this.role = system.role - this.name = system.name - additionalProperties(system.additionalProperties) + role = system.role + content = system.content + name = system.name + additionalProperties = system.additionalProperties.toMutableMap() } - fun content(content: String) = content(JsonField.of(content)) - - @JsonProperty("content") - @ExcludeMissing - fun content(content: JsonField) = apply { this.content = content } - fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun role(role: JsonField) = apply { this.role = role } + fun content(content: String) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [System]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): System = System( + checkRequired("role", role), content, - role, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): System = apply { + if (validated) { + return@apply + } + + role().validate() + content() + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + class Role @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - + 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 { + + val SYSTEM = of("system") + + fun of(value: String) = Role(JsonField.of(value)) + } + + /** An enum containing [Role]'s known values. */ + enum class Known { + SYSTEM + } + + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Role] 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, + /** + * An enum member indicating that [Role] 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 + 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + SYSTEM -> Known.SYSTEM + else -> throw BraintrustInvalidDataException("Unknown Role: $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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Role && this.value == other.value + return other is Role && value == other.value } override fun hashCode() = value.hashCode() override fun toString() = value.toString() + } - companion object { - - val SYSTEM = Role(JsonField.of("system")) - - fun of(value: String) = Role(JsonField.of(value)) - } - - enum class Known { - SYSTEM, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - enum class Value { - SYSTEM, - _UNKNOWN, - } + return other is System && + role == other.role && + content == other.content && + name == other.name && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - SYSTEM -> Value.SYSTEM - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { + Objects.hash(role, content, name, additionalProperties) + } - fun known(): Known = - when (this) { - SYSTEM -> Known.SYSTEM - else -> throw BraintrustInvalidDataException("Unknown Role: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "System{role=$role, content=$content, name=$name, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = User.Builder::class) - @NoAutoDetect class User + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val content: JsonField, private val role: JsonField, + private val content: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("role") + @ExcludeMissing + role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + ) : this(role, content, name, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun content(): Content? = content.getNullable("content") - fun role(): Role = role.getRequired("role") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") - @JsonProperty("content") @ExcludeMissing fun _content() = content + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("content") + @ExcludeMissing + fun _content(): JsonField = content - @JsonProperty("role") @ExcludeMissing fun _role() = role + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonProperty("name") @ExcludeMissing fun _name() = name + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): User = apply { - if (!validated) { - content() - role() - name() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is User && - this.content == other.content && - this.role == other.role && - this.name == other.name && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - role, - name, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "User{content=$content, role=$role, name=$name, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [User]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [User]. */ + class Builder internal constructor() { + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(user: User) = apply { - this.content = user.content - this.role = user.role - this.name = user.name - additionalProperties(user.additionalProperties) + role = user.role + content = user.content + name = user.name + additionalProperties = user.additionalProperties.toMutableMap() } + fun role(role: Role) = role(JsonField.of(role)) + + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun role(role: JsonField) = apply { this.role = role } + fun content(content: Content) = content(JsonField.of(content)) - @JsonProperty("content") - @ExcludeMissing + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [Content] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun content(content: JsonField) = apply { this.content = content } - fun role(role: Role) = role(JsonField.of(role)) + /** Alias for calling [content] with `Content.ofText(text)`. */ + fun content(text: String) = content(Content.ofText(text)) - @JsonProperty("role") - @ExcludeMissing - fun role(role: JsonField) = apply { this.role = role } + /** Alias for calling [content] with `Content.ofArray(array)`. */ + fun contentOfArray(array: List) = + content(Content.ofArray(array)) fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [User]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): User = User( + checkRequired("role", role), content, - role, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): User = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content()?.validate() + name() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (content.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Role + @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 { - val USER = Role(JsonField.of("user")) + val USER = of("user") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - USER, + USER } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Role] 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 { USER, + /** + * An enum member indicating that [Role] 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) { USER -> Value.USER 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { USER -> Known.USER else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Role && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } @JsonDeserialize(using = Content.Deserializer::class) @JsonSerialize(using = Content.Serializer::class) class Content private constructor( - private val string: String? = null, - private val chatCompletionContentParts: List? = - null, + private val text: String? = null, + private val array: List? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - - fun string(): String? = string + fun text(): String? = text - fun chatCompletionContentParts(): List? = - chatCompletionContentParts + fun array(): List? = array - fun isString(): Boolean = string != null + fun isText(): Boolean = text != null - fun isChatCompletionContentParts(): Boolean = - chatCompletionContentParts != null + fun isArray(): Boolean = array != null - fun asString(): String = string.getOrThrow("string") + fun asText(): String = text.getOrThrow("text") - fun asChatCompletionContentParts(): List = - chatCompletionContentParts.getOrThrow("chatCompletionContentParts") + fun asArray(): List = array.getOrThrow("array") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - string != null -> visitor.visitString(string) - chatCompletionContentParts != null -> - visitor.visitChatCompletionContentParts( - chatCompletionContentParts - ) + fun accept(visitor: Visitor): T = + when { + text != null -> visitor.visitText(text) + array != null -> visitor.visitArray(array) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): Content = apply { - if (!validated) { - if (string == null && chatCompletionContentParts == null) { - throw BraintrustInvalidDataException("Unknown Content: $_json") - } - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitText(text: String) {} + + override fun visitArray( + array: List + ) { + array.forEach { it.validate() } + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitText(text: String) = 1 + + override fun visitArray( + array: List + ) = array.sumOf { it.validity().toInt() } + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Content && - this.string == other.string && - this.chatCompletionContentParts == other.chatCompletionContentParts + return other is Content && text == other.text && array == other.array } - override fun hashCode(): Int { - return Objects.hash(string, chatCompletionContentParts) - } + override fun hashCode(): Int = Objects.hash(text, array) - override fun toString(): String { - return when { - string != null -> "Content{string=$string}" - chatCompletionContentParts != null -> - "Content{chatCompletionContentParts=$chatCompletionContentParts}" + override fun toString(): String = + when { + text != null -> "Content{text=$text}" + array != null -> "Content{array=$array}" _json != null -> "Content{_unknown=$_json}" else -> throw IllegalStateException("Invalid Content") } - } companion object { - fun ofString(string: String) = Content(string = string) + fun ofText(text: String) = Content(text = text) - fun ofChatCompletionContentParts( - chatCompletionContentParts: List - ) = Content(chatCompletionContentParts = chatCompletionContentParts) + fun ofArray(array: List) = + Content(array = array.toImmutable()) } + /** + * An interface that defines how to map each variant of [Content] to a value + * of type [T]. + */ interface Visitor { - fun visitString(string: String): T + fun visitText(text: String): T - fun visitChatCompletionContentParts( - chatCompletionContentParts: List - ): T + fun visitArray(array: List): T + /** + * Maps an unknown variant of [Content] to a value of type [T]. + * + * An instance of [Content] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown Content: $json") } } - class Deserializer : BaseDeserializer(Content::class) { + internal class Deserializer : BaseDeserializer(Content::class) { override fun ObjectCodec.deserialize(node: JsonNode): Content { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Content(string = it, _json = json) - } - tryDeserialize( - node, - jacksonTypeRef>() - ) - ?.let { - return Content( - chatCompletionContentParts = it, - _json = json - ) - } - return Content(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Content(text = it, _json = json) + }, + tryDeserialize( + node, + jacksonTypeRef< + List + >(), + ) + ?.let { Content(array = 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 object). + 0 -> Content(_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() + } } } - class Serializer : BaseSerializer(Content::class) { + internal class Serializer : BaseSerializer(Content::class) { override fun serialize( value: Content, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.string != null -> generator.writeObject(value.string) - value.chatCompletionContentParts != null -> - generator.writeObject(value.chatCompletionContentParts) + value.text != null -> generator.writeObject(value.text) + value.array != null -> generator.writeObject(value.array) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Content") } @@ -3459,133 +2883,142 @@ private constructor( @JsonSerialize(using = ChatCompletionContentPart.Serializer::class) class ChatCompletionContentPart private constructor( - private val chatCompletionContentPartText: - ChatCompletionContentPartText? = - null, - private val chatCompletionContentPartImage: - ChatCompletionContentPartImage? = - null, + private val text: ChatCompletionContentPartText? = null, + private val image: ChatCompletionContentPartImage? = null, private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - - fun chatCompletionContentPartText(): ChatCompletionContentPartText? = - chatCompletionContentPartText + fun text(): ChatCompletionContentPartText? = text - fun chatCompletionContentPartImage(): ChatCompletionContentPartImage? = - chatCompletionContentPartImage + fun image(): ChatCompletionContentPartImage? = image - fun isChatCompletionContentPartText(): Boolean = - chatCompletionContentPartText != null + fun isText(): Boolean = text != null - fun isChatCompletionContentPartImage(): Boolean = - chatCompletionContentPartImage != null + fun isImage(): Boolean = image != null - fun asChatCompletionContentPartText(): ChatCompletionContentPartText = - chatCompletionContentPartText.getOrThrow( - "chatCompletionContentPartText" - ) + fun asText(): ChatCompletionContentPartText = text.getOrThrow("text") - fun asChatCompletionContentPartImage(): ChatCompletionContentPartImage = - chatCompletionContentPartImage.getOrThrow( - "chatCompletionContentPartImage" - ) + fun asImage(): ChatCompletionContentPartImage = + image.getOrThrow("image") fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { - chatCompletionContentPartText != null -> - visitor.visitChatCompletionContentPartText( - chatCompletionContentPartText - ) - chatCompletionContentPartImage != null -> - visitor.visitChatCompletionContentPartImage( - chatCompletionContentPartImage - ) + fun accept(visitor: Visitor): T = + when { + text != null -> visitor.visitText(text) + image != null -> visitor.visitImage(image) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): ChatCompletionContentPart = apply { - if (!validated) { - if ( - chatCompletionContentPartText == null && - chatCompletionContentPartImage == null - ) { - throw BraintrustInvalidDataException( - "Unknown ChatCompletionContentPart: $_json" - ) - } - chatCompletionContentPartText?.validate() - chatCompletionContentPartImage?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitText( + text: ChatCompletionContentPartText + ) { + text.validate() + } + + override fun visitImage( + image: ChatCompletionContentPartImage + ) { + image.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitText( + text: ChatCompletionContentPartText + ) = text.validity() + + override fun visitImage( + image: ChatCompletionContentPartImage + ) = image.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is ChatCompletionContentPart && - this.chatCompletionContentPartText == - other.chatCompletionContentPartText && - this.chatCompletionContentPartImage == - other.chatCompletionContentPartImage + text == other.text && + image == other.image } - override fun hashCode(): Int { - return Objects.hash( - chatCompletionContentPartText, - chatCompletionContentPartImage - ) - } + override fun hashCode(): Int = Objects.hash(text, image) - override fun toString(): String { - return when { - chatCompletionContentPartText != null -> - "ChatCompletionContentPart{chatCompletionContentPartText=$chatCompletionContentPartText}" - chatCompletionContentPartImage != null -> - "ChatCompletionContentPart{chatCompletionContentPartImage=$chatCompletionContentPartImage}" + override fun toString(): String = + when { + text != null -> "ChatCompletionContentPart{text=$text}" + image != null -> "ChatCompletionContentPart{image=$image}" _json != null -> "ChatCompletionContentPart{_unknown=$_json}" else -> throw IllegalStateException( "Invalid ChatCompletionContentPart" ) } - } companion object { - fun ofChatCompletionContentPartText( - chatCompletionContentPartText: ChatCompletionContentPartText - ) = - ChatCompletionContentPart( - chatCompletionContentPartText = - chatCompletionContentPartText - ) + fun ofText(text: ChatCompletionContentPartText) = + ChatCompletionContentPart(text = text) - fun ofChatCompletionContentPartImage( - chatCompletionContentPartImage: ChatCompletionContentPartImage - ) = - ChatCompletionContentPart( - chatCompletionContentPartImage = - chatCompletionContentPartImage - ) + fun ofImage(image: ChatCompletionContentPartImage) = + ChatCompletionContentPart(image = image) } + /** + * An interface that defines how to map each variant of + * [ChatCompletionContentPart] to a value of type [T]. + */ interface Visitor { - fun visitChatCompletionContentPartText( - chatCompletionContentPartText: ChatCompletionContentPartText - ): T - - fun visitChatCompletionContentPartImage( - chatCompletionContentPartImage: ChatCompletionContentPartImage - ): T - + fun visitText(text: ChatCompletionContentPartText): T + + fun visitImage(image: ChatCompletionContentPartImage): T + + /** + * Maps an unknown variant of [ChatCompletionContentPart] to a value + * of type [T]. + * + * An instance of [ChatCompletionContentPart] 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 BraintrustInvalidDataException in the default + * implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException( "Unknown ChatCompletionContentPart: $json" @@ -3593,7 +3026,7 @@ private constructor( } } - class Deserializer : + internal class Deserializer : BaseDeserializer( ChatCompletionContentPart::class ) { @@ -3602,36 +3035,54 @@ private constructor( node: JsonNode ): ChatCompletionContentPart { val json = JsonValue.fromJsonNode(node) - tryDeserialize( - node, - jacksonTypeRef() - ) { - it.validate() - } - ?.let { - return ChatCompletionContentPart( - chatCompletionContentPartText = it, - _json = json - ) - } - tryDeserialize( - node, - jacksonTypeRef() - ) { - it.validate() - } - ?.let { - return ChatCompletionContentPart( - chatCompletionContentPartImage = it, - _json = json - ) - } - return ChatCompletionContentPart(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize( + node, + jacksonTypeRef< + ChatCompletionContentPartText + >(), + ) + ?.let { + ChatCompletionContentPart( + text = it, + _json = json, + ) + }, + tryDeserialize( + node, + jacksonTypeRef< + ChatCompletionContentPartImage + >(), + ) + ?.let { + ChatCompletionContentPart( + image = 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 -> ChatCompletionContentPart(_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() + } } } - class Serializer : + internal class Serializer : BaseSerializer( ChatCompletionContentPart::class ) { @@ -3639,17 +3090,11 @@ private constructor( override fun serialize( value: ChatCompletionContentPart, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { - value.chatCompletionContentPartText != null -> - generator.writeObject( - value.chatCompletionContentPartText - ) - value.chatCompletionContentPartImage != null -> - generator.writeObject( - value.chatCompletionContentPartImage - ) + value.text != null -> generator.writeObject(value.text) + value.image != null -> generator.writeObject(value.image) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException( @@ -3660,459 +3105,851 @@ private constructor( } } } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is User && + role == other.role && + content == other.content && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(role, content, name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "User{role=$role, content=$content, name=$name, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Assistant.Builder::class) - @NoAutoDetect class Assistant + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val role: JsonField, private val content: JsonField, private val functionCall: JsonField, private val name: JsonField, private val toolCalls: JsonField>, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("role") + @ExcludeMissing + role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("function_call") + @ExcludeMissing + functionCall: JsonField = JsonMissing.of(), + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + @JsonProperty("tool_calls") + @ExcludeMissing + toolCalls: JsonField> = JsonMissing.of(), + ) : this(role, content, functionCall, name, toolCalls, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun content(): String? = content.getNullable("content") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun functionCall(): FunctionCall? = functionCall.getNullable("function_call") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun name(): String? = name.getNullable("name") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ fun toolCalls(): List? = toolCalls.getNullable("tool_calls") - @JsonProperty("role") @ExcludeMissing fun _role() = role - - @JsonProperty("content") @ExcludeMissing fun _content() = content - + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("content") + @ExcludeMissing + fun _content(): JsonField = content + + /** + * Returns the raw JSON value of [functionCall]. + * + * Unlike [functionCall], this method doesn't throw if the JSON field has an + * unexpected type. + */ @JsonProperty("function_call") @ExcludeMissing - fun _functionCall() = functionCall - - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonProperty("tool_calls") @ExcludeMissing fun _toolCalls() = toolCalls - - @JsonAnyGetter + fun _functionCall(): JsonField = functionCall + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [toolCalls]. + * + * Unlike [toolCalls], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("tool_calls") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Assistant = apply { - if (!validated) { - role() - content() - functionCall()?.validate() - name() - toolCalls()?.forEach { it.validate() } - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun _toolCalls(): JsonField> = toolCalls - return other is Assistant && - this.role == other.role && - this.content == other.content && - this.functionCall == other.functionCall && - this.name == other.name && - this.toolCalls == other.toolCalls && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - role, - content, - functionCall, - name, - toolCalls, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Assistant{role=$role, content=$content, functionCall=$functionCall, name=$name, toolCalls=$toolCalls, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Assistant]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Assistant]. */ + class Builder internal constructor() { - private var role: JsonField = JsonMissing.of() + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() private var functionCall: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() - private var toolCalls: JsonField> = - JsonMissing.of() + private var toolCalls: + JsonField>? = + null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(assistant: Assistant) = apply { - this.role = assistant.role - this.content = assistant.content - this.functionCall = assistant.functionCall - this.name = assistant.name - this.toolCalls = assistant.toolCalls - additionalProperties(assistant.additionalProperties) + role = assistant.role + content = assistant.content + functionCall = assistant.functionCall + name = assistant.name + toolCalls = assistant.toolCalls.map { it.toMutableList() } + additionalProperties = assistant.additionalProperties.toMutableMap() } fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun role(role: JsonField) = apply { this.role = role } - fun content(content: String) = content(JsonField.of(content)) + fun content(content: String?) = content(JsonField.ofNullable(content)) - @JsonProperty("content") - @ExcludeMissing + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun content(content: JsonField) = apply { this.content = content } - fun functionCall(functionCall: FunctionCall) = - functionCall(JsonField.of(functionCall)) + fun functionCall(functionCall: FunctionCall?) = + functionCall(JsonField.ofNullable(functionCall)) - @JsonProperty("function_call") - @ExcludeMissing + /** + * Sets [Builder.functionCall] to an arbitrary JSON value. + * + * You should usually call [Builder.functionCall] with a well-typed + * [FunctionCall] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ fun functionCall(functionCall: JsonField) = apply { this.functionCall = functionCall } - fun name(name: String) = name(JsonField.of(name)) + fun name(name: String?) = name(JsonField.ofNullable(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } - fun toolCalls(toolCalls: List) = - toolCalls(JsonField.of(toolCalls)) - - @JsonProperty("tool_calls") - @ExcludeMissing + fun toolCalls(toolCalls: List?) = + toolCalls(JsonField.ofNullable(toolCalls)) + + /** + * Sets [Builder.toolCalls] to an arbitrary JSON value. + * + * You should usually call [Builder.toolCalls] with a well-typed + * `List` value instead. This method is + * primarily for setting the field to an undocumented or not yet supported + * value. + */ fun toolCalls(toolCalls: JsonField>) = apply { - this.toolCalls = toolCalls + this.toolCalls = toolCalls.map { it.toMutableList() } } + /** + * Adds a single [ChatCompletionMessageToolCall] to [toolCalls]. + * + * @throws IllegalStateException if the field was previously set to a + * non-list. + */ + fun addToolCall(toolCall: ChatCompletionMessageToolCall) = apply { + toolCalls = + (toolCalls ?: JsonField.of(mutableListOf())).also { + checkKnown("toolCalls", it).add(toolCall) + } + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Assistant]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Assistant = Assistant( - role, + checkRequired("role", role), content, functionCall, name, - toolCalls.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + (toolCalls ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Assistant = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content() + functionCall()?.validate() + name() + toolCalls()?.forEach { it.validate() } + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) + + (functionCall.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (toolCalls.asKnown()?.sumOf { it.validity().toInt() } ?: 0) - override fun toString() = value.toString() + class Role + @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 { - val ASSISTANT = Role(JsonField.of("assistant")) + val ASSISTANT = of("assistant") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - ASSISTANT, + ASSISTANT } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Role] 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 { ASSISTANT, + /** + * An enum member indicating that [Role] 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) { ASSISTANT -> Value.ASSISTANT 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { ASSISTANT -> Known.ASSISTANT else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Role && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } - @JsonDeserialize(builder = FunctionCall.Builder::class) - @NoAutoDetect class FunctionCall + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val arguments: JsonField, private val name: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("arguments") + @ExcludeMissing + arguments: JsonField = JsonMissing.of(), + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + ) : this(arguments, name, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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(): String = arguments.getRequired("arguments") + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - @JsonProperty("arguments") @ExcludeMissing fun _arguments() = arguments - - @JsonProperty("name") @ExcludeMissing fun _name() = name - - @JsonAnyGetter + /** + * 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 _additionalProperties(): Map = additionalProperties - - fun validate(): FunctionCall = apply { - if (!validated) { - arguments() - name() - validated = true - } - } - - fun toBuilder() = Builder().from(this) + fun _arguments(): JsonField = arguments - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - return other is FunctionCall && - this.arguments == other.arguments && - this.name == other.name && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - arguments, - name, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "FunctionCall{arguments=$arguments, name=$name, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of + * [FunctionCall]. + * + * The following fields are required: + * ```kotlin + * .arguments() + * .name() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [FunctionCall]. */ + class Builder internal constructor() { - private var arguments: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var arguments: JsonField? = null + private var name: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(functionCall: FunctionCall) = apply { - this.arguments = functionCall.arguments - this.name = functionCall.name - additionalProperties(functionCall.additionalProperties) + arguments = functionCall.arguments + name = functionCall.name + additionalProperties = + functionCall.additionalProperties.toMutableMap() } fun arguments(arguments: String) = arguments(JsonField.of(arguments)) - @JsonProperty("arguments") - @ExcludeMissing + /** + * Sets [Builder.arguments] to an arbitrary JSON value. + * + * You should usually call [Builder.arguments] with a well-typed + * [String] 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 } fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [FunctionCall]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```kotlin + * .arguments() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): FunctionCall = FunctionCall( - arguments, - name, - additionalProperties.toUnmodifiable(), + checkRequired("arguments", arguments), + checkRequired("name", name), + additionalProperties.toMutableMap(), ) } - } - } - - @JsonDeserialize(builder = Tool.Builder::class) - @NoAutoDetect - class Tool - private constructor( - private val content: JsonField, - private val role: JsonField, - private val toolCallId: JsonField, - private val additionalProperties: Map, - ) { - private var validated: Boolean = false + private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): FunctionCall = apply { + if (validated) { + return@apply + } - fun content(): String? = content.getNullable("content") + arguments() + name() + validated = true + } - fun role(): Role = role.getRequired("role") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun toolCallId(): String? = toolCallId.getNullable("tool_call_id") + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (arguments.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) - @JsonProperty("content") @ExcludeMissing fun _content() = content + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("role") @ExcludeMissing fun _role() = role + return other is FunctionCall && + arguments == other.arguments && + name == other.name && + additionalProperties == other.additionalProperties + } - @JsonProperty("tool_call_id") @ExcludeMissing fun _toolCallId() = toolCallId + private val hashCode: Int by lazy { + Objects.hash(arguments, name, additionalProperties) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode(): Int = hashCode - fun validate(): Tool = apply { - if (!validated) { - content() - role() - toolCallId() - validated = true - } + override fun toString() = + "FunctionCall{arguments=$arguments, name=$name, additionalProperties=$additionalProperties}" } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Tool && - this.content == other.content && - this.role == other.role && - this.toolCallId == other.toolCallId && - this.additionalProperties == other.additionalProperties + return other is Assistant && + role == other.role && + content == other.content && + functionCall == other.functionCall && + name == other.name && + toolCalls == other.toolCalls && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - role, - toolCallId, - additionalProperties, - ) - } - return hashCode + private val hashCode: Int by lazy { + Objects.hash( + role, + content, + functionCall, + name, + toolCalls, + additionalProperties, + ) } + override fun hashCode(): Int = hashCode + override fun toString() = - "Tool{content=$content, role=$role, toolCallId=$toolCallId, additionalProperties=$additionalProperties}" + "Assistant{role=$role, content=$content, functionCall=$functionCall, name=$name, toolCalls=$toolCalls, additionalProperties=$additionalProperties}" + } + + class Tool + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val role: JsonField, + private val content: JsonField, + private val toolCallId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("role") + @ExcludeMissing + role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("tool_call_id") + @ExcludeMissing + toolCallId: JsonField = JsonMissing.of(), + ) : this(role, content, toolCallId, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun content(): String? = content.getNullable("content") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun toolCallId(): String? = toolCallId.getNullable("tool_call_id") + + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("content") + @ExcludeMissing + fun _content(): JsonField = content + + /** + * Returns the raw JSON value of [toolCallId]. + * + * Unlike [toolCallId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("tool_call_id") + @ExcludeMissing + fun _toolCallId(): JsonField = toolCallId + + @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 [Tool]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Tool]. */ + class Builder internal constructor() { + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var toolCallId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(tool: Tool) = apply { - this.content = tool.content - this.role = tool.role - this.toolCallId = tool.toolCallId - additionalProperties(tool.additionalProperties) + role = tool.role + content = tool.content + toolCallId = tool.toolCallId + additionalProperties = tool.additionalProperties.toMutableMap() } - fun content(content: String) = content(JsonField.of(content)) - - @JsonProperty("content") - @ExcludeMissing - fun content(content: JsonField) = apply { this.content = content } - fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun role(role: JsonField) = apply { this.role = role } + fun content(content: String) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + fun toolCallId(toolCallId: String) = toolCallId(JsonField.of(toolCallId)) - @JsonProperty("tool_call_id") - @ExcludeMissing + /** + * Sets [Builder.toolCallId] to an arbitrary JSON value. + * + * You should usually call [Builder.toolCallId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun toolCallId(toolCallId: JsonField) = apply { this.toolCallId = toolCallId } @@ -4120,556 +3957,1069 @@ private constructor( fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Tool]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Tool = Tool( + checkRequired("role", role), content, - role, toolCallId, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Tool = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content() + toolCallId() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) + + (if (toolCallId.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Role + @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 { - val TOOL = Role(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - TOOL, + TOOL } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Role] 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 { TOOL, + /** + * An enum member indicating that [Role] 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) { TOOL -> Value.TOOL else -> Value._UNKNOWN } - fun known(): Known = - when (this) { - TOOL -> Known.TOOL - else -> throw BraintrustInvalidDataException("Unknown Role: $value") - } + /** + * 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + TOOL -> Known.TOOL + else -> throw BraintrustInvalidDataException("Unknown Role: $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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Role && 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 Tool && + role == other.role && + content == other.content && + toolCallId == other.toolCallId && + additionalProperties == other.additionalProperties + } - fun asString(): String = _value().asStringOrThrow() + private val hashCode: Int by lazy { + Objects.hash(role, content, toolCallId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Tool{role=$role, content=$content, toolCallId=$toolCallId, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val content: JsonField, private val name: JsonField, private val role: JsonField, - private val additionalProperties: Map, + private val content: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun content(): String? = content.getNullable("content") - + @JsonCreator + private constructor( + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + @JsonProperty("role") + @ExcludeMissing + role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + ) : this(name, role, content, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") - @JsonProperty("content") @ExcludeMissing fun _content() = content + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun content(): String? = content.getNullable("content") - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("content") + @ExcludeMissing + fun _content(): JsonField = content - @JsonProperty("role") @ExcludeMissing fun _role() = role + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - content() - name() - role() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Function && - this.content == other.content && - this.name == other.name && - this.role == other.role && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - content, - name, - role, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Function{content=$content, name=$name, role=$role, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Function]. + * + * The following fields are required: + * ```kotlin + * .name() + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Function]. */ + class Builder internal constructor() { + private var name: JsonField? = null + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(function: Function) = apply { - this.content = function.content - this.name = function.name - this.role = function.role - additionalProperties(function.additionalProperties) + name = function.name + role = function.role + content = function.content + additionalProperties = function.additionalProperties.toMutableMap() } - fun content(content: String) = content(JsonField.of(content)) - - @JsonProperty("content") - @ExcludeMissing - fun content(content: JsonField) = apply { this.content = content } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun role(role: JsonField) = apply { this.role = role } + fun content(content: String) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Function = Function( + checkRequired("name", name), + checkRequired("role", role), content, - name, - role, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Function = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + role().validate() + content() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Role + @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 { - val FUNCTION = Role(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - FUNCTION, + FUNCTION } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Role] 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 { FUNCTION, + /** + * An enum member indicating that [Role] 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) { FUNCTION -> Value.FUNCTION 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { FUNCTION -> Known.FUNCTION else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Fallback.Builder::class) - @NoAutoDetect - class Fallback - private constructor( - private val role: JsonField, - private val content: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Role = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun role(): Role = role.getRequired("role") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun content(): String? = content.getNullable("content") + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("role") @ExcludeMissing fun _role() = role + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("content") @ExcludeMissing fun _content() = content + return other is Role && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Fallback = apply { - if (!validated) { - role() - content() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Fallback && - this.role == other.role && - this.content == other.content && - this.additionalProperties == other.additionalProperties + return other is Function && + name == other.name && + role == other.role && + content == other.content && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - role, - content, - additionalProperties, - ) - } - return hashCode + private val hashCode: Int by lazy { + Objects.hash(name, role, content, additionalProperties) } + override fun hashCode(): Int = hashCode + override fun toString() = - "Fallback{role=$role, content=$content, additionalProperties=$additionalProperties}" + "Function{name=$name, role=$role, content=$content, additionalProperties=$additionalProperties}" + } + + class Fallback + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val role: JsonField, + private val content: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("role") + @ExcludeMissing + role: JsonField = JsonMissing.of(), + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + ) : this(role, content, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 role(): Role = role.getRequired("role") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun content(): String? = content.getNullable("content") + + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("content") + @ExcludeMissing + fun _content(): JsonField = content + + @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 [Fallback]. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Fallback]. */ + class Builder internal constructor() { - private var role: JsonField = JsonMissing.of() + private var role: JsonField? = null private var content: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(fallback: Fallback) = apply { - this.role = fallback.role - this.content = fallback.content - additionalProperties(fallback.additionalProperties) + role = fallback.role + content = fallback.content + additionalProperties = fallback.additionalProperties.toMutableMap() } fun role(role: Role) = role(JsonField.of(role)) - @JsonProperty("role") - @ExcludeMissing + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun role(role: JsonField) = apply { this.role = role } - fun content(content: String) = content(JsonField.of(content)) + fun content(content: String?) = content(JsonField.ofNullable(content)) - @JsonProperty("content") - @ExcludeMissing + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ fun content(content: JsonField) = apply { this.content = content } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Fallback]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Fallback = Fallback( - role, + checkRequired("role", role), content, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Role - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value + fun validate(): Fallback = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + role().validate() + content() + validated = true + } - return other is Role && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (role.asKnown()?.validity() ?: 0) + + (if (content.asKnown() == null) 0 else 1) - override fun toString() = value.toString() + class Role + @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 { - val MODEL = Role(JsonField.of("model")) + val MODEL = of("model") fun of(value: String) = Role(JsonField.of(value)) } + /** An enum containing [Role]'s known values. */ enum class Known { - MODEL, + MODEL } + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Role] 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 { MODEL, + /** + * An enum member indicating that [Role] 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) { MODEL -> Value.MODEL 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ fun known(): Known = when (this) { MODEL -> Known.MODEL else -> throw BraintrustInvalidDataException("Unknown Role: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Role && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } - } - } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + return other is Fallback && + role == other.role && + content == other.content && + additionalProperties == other.additionalProperties + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + private val hashCode: Int by lazy { + Objects.hash(role, content, additionalProperties) } - return other is Type && this.value == other.value - } + override fun hashCode(): Int = hashCode - override fun hashCode() = value.hashCode() + override fun toString() = + "Fallback{role=$role, content=$content, additionalProperties=$additionalProperties}" + } + } - override fun toString() = value.toString() + 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 { - val CHAT = Type(JsonField.of("chat")) + val CHAT = of("chat") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - CHAT, + CHAT } + /** + * 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 { CHAT, + /** + * 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) { CHAT -> Value.CHAT 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { CHAT -> Known.CHAT else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } - - @JsonDeserialize(builder = NullableVariant.Builder::class) - @NoAutoDetect - class NullableVariant - private constructor( - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - private var hashCode: Int = 0 + private var validated: Boolean = false - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun validate(): Type = apply { + if (validated) { + return@apply + } - fun validate(): NullableVariant = apply { - if (!validated) { + known() validated = true } - } - fun toBuilder() = Builder().from(this) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - return other is NullableVariant && - this.additionalProperties == other.additionalProperties - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) + return other is Type && value == other.value } - return hashCode - } - override fun toString() = "NullableVariant{additionalProperties=$additionalProperties}" - - companion object { + override fun hashCode() = value.hashCode() - fun builder() = Builder() + override fun toString() = value.toString() } - class Builder { - - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(nullableVariant: NullableVariant) = apply { - additionalProperties(nullableVariant.additionalProperties) + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + return other is Chat && + messages == other.messages && + type == other.type && + tools == other.tools && + additionalProperties == other.additionalProperties + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + private val hashCode: Int by lazy { + Objects.hash(messages, type, tools, additionalProperties) + } - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + override fun hashCode(): Int = hashCode - fun build(): NullableVariant = - NullableVariant(additionalProperties.toUnmodifiable()) - } + override fun toString() = + "Chat{messages=$messages, type=$type, tools=$tools, additionalProperties=$additionalProperties}" } } @@ -4682,8 +5032,6 @@ private constructor( private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun function(): Function? = function fun global(): Global? = global @@ -4698,47 +5046,76 @@ private constructor( fun _json(): JsonValue? = _json - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { function != null -> visitor.visitFunction(function) global != null -> visitor.visitGlobal(global) else -> visitor.unknown(_json) } - } + + private var validated: Boolean = false fun validate(): ToolFunction = apply { - if (!validated) { - if (function == null && global == null) { - throw BraintrustInvalidDataException("Unknown ToolFunction: $_json") - } - function?.validate() - global?.validate() - validated = true + if (validated) { + return@apply } + + accept( + object : Visitor { + override fun visitFunction(function: Function) { + function.validate() + } + + override fun visitGlobal(global: Global) { + global.validate() + } + } + ) + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitFunction(function: Function) = function.validity() + + override fun visitGlobal(global: Global) = global.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is ToolFunction && - this.function == other.function && - this.global == other.global + return other is ToolFunction && function == other.function && global == other.global } - override fun hashCode(): Int { - return Objects.hash(function, global) - } + override fun hashCode(): Int = Objects.hash(function, global) - override fun toString(): String { - return when { + override fun toString(): String = + when { function != null -> "ToolFunction{function=$function}" global != null -> "ToolFunction{global=$global}" _json != null -> "ToolFunction{_unknown=$_json}" else -> throw IllegalStateException("Invalid ToolFunction") } - } companion object { @@ -4747,40 +5124,67 @@ private constructor( fun ofGlobal(global: Global) = ToolFunction(global = global) } + /** + * An interface that defines how to map each variant of [ToolFunction] to a value of type + * [T]. + */ interface Visitor { fun visitFunction(function: Function): T fun visitGlobal(global: Global): T + /** + * Maps an unknown variant of [ToolFunction] to a value of type [T]. + * + * An instance of [ToolFunction] 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 BraintrustInvalidDataException in the default implementation. + */ fun unknown(json: JsonValue?): T { throw BraintrustInvalidDataException("Unknown ToolFunction: $json") } } - class Deserializer : BaseDeserializer(ToolFunction::class) { + internal class Deserializer : BaseDeserializer(ToolFunction::class) { override fun ObjectCodec.deserialize(node: JsonNode): ToolFunction { val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return ToolFunction(function = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return ToolFunction(global = it, _json = json) - } - return ToolFunction(_json = json) + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + ToolFunction(function = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ToolFunction(global = 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 -> ToolFunction(_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() + } } } - class Serializer : BaseSerializer(ToolFunction::class) { + internal class Serializer : BaseSerializer(ToolFunction::class) { override fun serialize( value: ToolFunction, generator: JsonGenerator, - provider: SerializerProvider + provider: SerializerProvider, ) { when { value.function != null -> generator.writeObject(value.function) @@ -4791,104 +5195,116 @@ private constructor( } } - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val type: JsonField, private val id: JsonField, - private val additionalProperties: Map, + private val type: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(id, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 BraintrustInvalidDataException 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") - fun id(): String = id.getRequired("id") + /** + * 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 - @JsonProperty("type") @ExcludeMissing fun _type() = type + /** + * 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 - @JsonProperty("id") @ExcludeMissing fun _id() = id + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - type() - id() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Function && - this.type == other.type && - this.id == other.id && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - id, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Function{type=$type, id=$id, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [Function]. + * + * The following fields are required: + * ```kotlin + * .id() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Function]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var id: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(function: Function) = apply { - this.type = function.type - this.id = function.id - additionalProperties(function.additionalProperties) + id = function.id + type = function.type + additionalProperties = function.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun id(id: String) = id(JsonField.of(id)) - @JsonProperty("id") - @ExcludeMissing + /** + * 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 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -4896,164 +5312,316 @@ private constructor( 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Function = Function( - type, - id, - additionalProperties.toUnmodifiable(), + checkRequired("id", id), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Function = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + id() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val FUNCTION = Type(JsonField.of("function")) + val FUNCTION = of("function") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - FUNCTION, + FUNCTION } + /** + * 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 { FUNCTION, + /** + * 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) { FUNCTION -> Value.FUNCTION 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { FUNCTION -> Known.FUNCTION else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() - } - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") - @JsonDeserialize(builder = Global.Builder::class) - @NoAutoDetect - class Global - private constructor( - private val type: JsonField, - private val name: JsonField, - private val additionalProperties: Map, - ) { + private var validated: Boolean = false - private var validated: Boolean = false + fun validate(): Type = apply { + if (validated) { + return@apply + } - private var hashCode: Int = 0 + known() + validated = true + } - fun type(): Type = type.getRequired("type") + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun name(): String = name.getRequired("name") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - @JsonProperty("type") @ExcludeMissing fun _type() = type + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JsonProperty("name") @ExcludeMissing fun _name() = name + return other is Type && value == other.value + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + override fun hashCode() = value.hashCode() - fun validate(): Global = apply { - if (!validated) { - type() - name() - validated = true - } + override fun toString() = value.toString() } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Global && - this.type == other.type && - this.name == other.name && - this.additionalProperties == other.additionalProperties + return other is Function && + id == other.id && + type == other.type && + additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - name, - additionalProperties, - ) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(id, type, additionalProperties) } + + override fun hashCode(): Int = hashCode override fun toString() = - "Global{type=$type, name=$name, additionalProperties=$additionalProperties}" + "Function{id=$id, type=$type, additionalProperties=$additionalProperties}" + } + + class Global + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [Global]. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Global]. */ + class Builder internal constructor() { - private var type: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var name: JsonField? = null + private var type: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(global: Global) = apply { - this.type = global.type - this.name = global.name - additionalProperties(global.additionalProperties) + name = global.name + type = global.type + additionalProperties = global.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - fun name(name: String) = name(JsonField.of(name)) - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun name(name: JsonField) = apply { this.name = name } + 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() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = @@ -5061,64 +5629,227 @@ private constructor( 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 [Global]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Global = Global( - type, - name, - additionalProperties.toUnmodifiable(), + checkRequired("name", name), + checkRequired("type", type), + additionalProperties.toMutableMap(), ) } - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): Global = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + name() + type().validate() + validated = true + } - return other is Type && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (type.asKnown()?.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 { - val GLOBAL = Type(JsonField.of("global")) + val GLOBAL = of("global") fun of(value: String) = Type(JsonField.of(value)) } + /** An enum containing [Type]'s known values. */ enum class Known { - GLOBAL, + GLOBAL } + /** + * 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 { GLOBAL, + /** + * 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) { GLOBAL -> Value.GLOBAL 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ fun known(): Known = when (this) { GLOBAL -> Known.GLOBAL else -> throw BraintrustInvalidDataException("Unknown Type: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Global && + name == other.name && + type == other.type && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { Objects.hash(name, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Global{name=$name, type=$type, additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } + + return other is PromptData && + options == other.options && + origin == other.origin && + parser == other.parser && + prompt == other.prompt && + toolFunctions == other.toolFunctions && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(options, origin, parser, prompt, toolFunctions, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PromptData{options=$options, origin=$origin, parser=$parser, prompt=$prompt, toolFunctions=$toolFunctions, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptDeleteParams.kt index 0d83f9f9..c4daa0e9 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a prompt object by its id */ class PromptDeleteParams -constructor( - private val promptId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val promptId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun promptId(): String = promptId + /** Prompt id */ + fun promptId(): String? = promptId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> promptId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): PromptDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [PromptDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [PromptDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var promptId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(promptDeleteParams: PromptDeleteParams) = apply { + promptId = promptDeleteParams.promptId + additionalHeaders = promptDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = promptDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = promptDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Prompt id */ + fun promptId(promptId: String?) = apply { this.promptId = promptId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is PromptDeleteParams && - this.promptId == other.promptId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - promptId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "PromptDeleteParams{promptId=$promptId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var promptId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(promptDeleteParams: PromptDeleteParams) = apply { - this.promptId = promptDeleteParams.promptId - additionalQueryParams(promptDeleteParams.additionalQueryParams) - additionalHeaders(promptDeleteParams.additionalHeaders) - additionalBodyProperties(promptDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Prompt id */ - fun promptId(promptId: String) = apply { this.promptId = promptId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [PromptDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): PromptDeleteParams = PromptDeleteParams( - checkNotNull(promptId) { "`promptId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + promptId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> promptId ?: "" + 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 PromptDeleteParams && + promptId == other.promptId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(promptId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "PromptDeleteParams{promptId=$promptId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPage.kt index 9127c5eb..5212e6bc 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPage.kt @@ -2,172 +2,120 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.PromptService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see PromptService.list */ class PromptListPage private constructor( - private val promptsService: PromptService, + private val service: PromptService, private val params: PromptListParams, - private val response: Response, -) { + private val response: PromptListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [PromptListPageResponse], but gracefully handles missing data. + * + * @see PromptListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is PromptListPage && - this.promptsService == other.promptsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - promptsService, - params, - response, - ) - } - - override fun toString() = - "PromptListPage{promptsService=$promptsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPageParams(): PromptListParams? { - if (!hasNextPage()) { - return null - } - - return if (params.endingBefore() != null) { - PromptListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): PromptListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - PromptListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): PromptListPage? { - return getNextPageParams()?.let { promptsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(promptsService: PromptService, params: PromptListParams, response: Response) = - PromptListPage( - promptsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): PromptListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): PromptListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): PromptListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [PromptListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [PromptListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: PromptService? = null + private var params: PromptListParams? = null + private var response: PromptListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(promptListPage: PromptListPage) = apply { + service = promptListPage.service + params = promptListPage.params + response = promptListPage.response } - override fun toString() = - "PromptListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: PromptService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: PromptListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: PromptListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [PromptListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PromptListPage = + PromptListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is PromptListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: PromptListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = "PromptListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPageAsync.kt index 6c751584..194f33bb 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPageAsync.kt @@ -2,174 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.PromptServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see PromptServiceAsync.list */ class PromptListPageAsync private constructor( - private val promptsService: PromptServiceAsync, + private val service: PromptServiceAsync, private val params: PromptListParams, - private val response: Response, -) { + private val response: PromptListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [PromptListPageResponse], but gracefully handles missing data. + * + * @see PromptListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is PromptListPageAsync && - this.promptsService == other.promptsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - promptsService, - params, - response, - ) - } - - override fun toString() = - "PromptListPageAsync{promptsService=$promptsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): PromptListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - PromptListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): PromptListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - PromptListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): PromptListPageAsync? { - return getNextPageParams()?.let { promptsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(promptsService: PromptServiceAsync, params: PromptListParams, response: Response) = - PromptListPageAsync( - promptsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): PromptListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): PromptListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): PromptListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [PromptListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [PromptListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: PromptServiceAsync? = null + private var params: PromptListParams? = null + private var response: PromptListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(promptListPageAsync: PromptListPageAsync) = apply { + service = promptListPageAsync.service + params = promptListPageAsync.params + response = promptListPageAsync.response } - override fun toString() = - "PromptListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: PromptServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: PromptListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: PromptListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [PromptListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PromptListPageAsync = + PromptListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is PromptListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: PromptListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "PromptListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPageResponse.kt new file mode 100644 index 00000000..63c99f60 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListPageResponse.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 PromptListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of prompt objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [PromptListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [PromptListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(promptListPageResponse: PromptListPageResponse) = apply { + objects = promptListPageResponse.objects.map { it.toMutableList() } + additionalProperties = promptListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of prompt objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Prompt] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Prompt) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [PromptListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PromptListPageResponse = + PromptListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): PromptListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PromptListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PromptListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListParams.kt index 4ed7664b..92074dfa 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all prompts. The prompts are sorted by creation date, with the most recently-created + * prompts coming first + */ class PromptListParams -constructor( +private constructor( private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, @@ -31,101 +25,78 @@ constructor( private val slug: String?, private val startingAfter: String?, private val version: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Project id */ fun projectId(): String? = projectId + /** Name of the project to search for */ fun projectName(): String? = projectName + /** Name of the prompt to search for */ fun promptName(): String? = promptName + /** Retrieve prompt with a specific slug */ fun slug(): String? = slug + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter + /** + * Retrieve prompt at a specific version. + * + * The version id can either be a transaction id (e.g. '1000192656880881099') or a version + * identifier (e.g. '81cd05ee665fdfb3'). + */ fun version(): String? = version - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.projectId?.let { params.put("project_id", listOf(it.toString())) } - this.projectName?.let { params.put("project_name", listOf(it.toString())) } - this.promptName?.let { params.put("prompt_name", listOf(it.toString())) } - this.slug?.let { params.put("slug", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - this.version?.let { params.put("version", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is PromptListParams && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.projectId == other.projectId && - this.projectName == other.projectName && - this.promptName == other.promptName && - this.slug == other.slug && - this.startingAfter == other.startingAfter && - this.version == other.version && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - ids, - limit, - orgName, - projectId, - projectName, - promptName, - slug, - startingAfter, - version, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "PromptListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, promptName=$promptName, slug=$slug, startingAfter=$startingAfter, version=$version, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): PromptListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [PromptListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [PromptListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var ids: Ids? = null @@ -137,22 +108,22 @@ constructor( private var slug: String? = null private var startingAfter: String? = null private var version: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(promptListParams: PromptListParams) = apply { - this.endingBefore = promptListParams.endingBefore - this.ids = promptListParams.ids - this.limit = promptListParams.limit - this.orgName = promptListParams.orgName - this.projectId = promptListParams.projectId - this.projectName = promptListParams.projectName - this.promptName = promptListParams.promptName - this.slug = promptListParams.slug - this.startingAfter = promptListParams.startingAfter - this.version = promptListParams.version - additionalQueryParams(promptListParams.additionalQueryParams) - additionalHeaders(promptListParams.additionalHeaders) + endingBefore = promptListParams.endingBefore + ids = promptListParams.ids + limit = promptListParams.limit + orgName = promptListParams.orgName + projectId = promptListParams.projectId + projectName = promptListParams.projectName + promptName = promptListParams.promptName + slug = promptListParams.slug + startingAfter = promptListParams.startingAfter + version = promptListParams.version + additionalHeaders = promptListParams.additionalHeaders.toBuilder() + additionalQueryParams = promptListParams.additionalQueryParams.toBuilder() } /** @@ -162,43 +133,44 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Project id */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun projectId(projectId: String?) = apply { this.projectId = projectId } /** Name of the project to search for */ - fun projectName(projectName: String) = apply { this.projectName = projectName } + fun projectName(projectName: String?) = apply { this.projectName = projectName } /** Name of the prompt to search for */ - fun promptName(promptName: String) = apply { this.promptName = promptName } + fun promptName(promptName: String?) = apply { this.promptName = promptName } /** Retrieve prompt with a specific slug */ - fun slug(slug: String) = apply { this.slug = slug } + fun slug(slug: String?) = apply { this.slug = slug } /** * Pagination cursor id. @@ -207,7 +179,7 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } /** * Retrieve prompt at a specific version. @@ -215,48 +187,111 @@ constructor( * The version id can either be a transaction id (e.g. '1000192656880881099') or a version * identifier (e.g. '81cd05ee665fdfb3'). */ - fun version(version: String) = apply { this.version = version } + fun version(version: String?) = apply { this.version = version } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [PromptListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): PromptListParams = PromptListParams( endingBefore, @@ -269,22 +304,50 @@ constructor( slug, startingAfter, version, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + projectId?.let { put("project_id", it) } + projectName?.let { put("project_name", it) } + promptName?.let { put("prompt_name", it) } + slug?.let { put("slug", it) } + startingAfter?.let { put("starting_after", it) } + version?.let { put("version", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -297,93 +360,82 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is PromptListParams && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + projectId == other.projectId && + projectName == other.projectName && + promptName == other.promptName && + slug == other.slug && + startingAfter == other.startingAfter && + version == other.version && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + ids, + limit, + orgName, + projectId, + projectName, + promptName, + slug, + startingAfter, + version, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "PromptListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, projectId=$projectId, projectName=$projectName, promptName=$promptName, slug=$slug, startingAfter=$startingAfter, version=$version, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptOptions.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptOptions.kt new file mode 100644 index 00000000..b0bebebd --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptOptions.kt @@ -0,0 +1,5445 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.BaseDeserializer +import com.braintrustdata.api.core.BaseSerializer +import com.braintrustdata.api.core.Enum +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.allMaxBy +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.getOrThrow +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 + +class PromptOptions +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val model: JsonField, + private val params: JsonField, + private val position: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("params") @ExcludeMissing params: JsonField = JsonMissing.of(), + @JsonProperty("position") @ExcludeMissing position: JsonField = JsonMissing.of(), + ) : this(model, params, position, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun model(): String? = model.getNullable("model") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun params(): Params? = params.getNullable("params") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun position(): String? = position.getNullable("position") + + /** + * 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 [params]. + * + * Unlike [params], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("params") @ExcludeMissing fun _params(): JsonField = params + + /** + * Returns the raw JSON value of [position]. + * + * Unlike [position], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("position") @ExcludeMissing fun _position(): JsonField = position + + @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 [PromptOptions]. */ + fun builder() = Builder() + } + + /** A builder for [PromptOptions]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var params: JsonField = JsonMissing.of() + private var position: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(promptOptions: PromptOptions) = apply { + model = promptOptions.model + params = promptOptions.params + position = promptOptions.position + additionalProperties = promptOptions.additionalProperties.toMutableMap() + } + + 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 params(params: Params) = params(JsonField.of(params)) + + /** + * Sets [Builder.params] to an arbitrary JSON value. + * + * You should usually call [Builder.params] with a well-typed [Params] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun params(params: JsonField) = apply { this.params = params } + + /** Alias for calling [params] with `Params.ofOpenAIModel(openaiModel)`. */ + fun params(openaiModel: Params.OpenAIModelParams) = + params(Params.ofOpenAIModel(openaiModel)) + + /** Alias for calling [params] with `Params.ofAnthropicModel(anthropicModel)`. */ + fun params(anthropicModel: Params.AnthropicModelParams) = + params(Params.ofAnthropicModel(anthropicModel)) + + /** Alias for calling [params] with `Params.ofGoogleModel(googleModel)`. */ + fun params(googleModel: Params.GoogleModelParams) = + params(Params.ofGoogleModel(googleModel)) + + /** Alias for calling [params] with `Params.ofWindowAiModel(windowAiModel)`. */ + fun params(windowAiModel: Params.WindowAiModelParams) = + params(Params.ofWindowAiModel(windowAiModel)) + + /** Alias for calling [params] with `Params.ofJsCompletion(jsCompletion)`. */ + fun params(jsCompletion: Params.JsCompletionParams) = + params(Params.ofJsCompletion(jsCompletion)) + + fun position(position: String) = position(JsonField.of(position)) + + /** + * Sets [Builder.position] to an arbitrary JSON value. + * + * You should usually call [Builder.position] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun position(position: JsonField) = apply { this.position = position } + + 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 [PromptOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PromptOptions = + PromptOptions(model, params, position, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): PromptOptions = apply { + if (validated) { + return@apply + } + + model() + params()?.validate() + position() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (model.asKnown() == null) 0 else 1) + + (params.asKnown()?.validity() ?: 0) + + (if (position.asKnown() == null) 0 else 1) + + @JsonDeserialize(using = Params.Deserializer::class) + @JsonSerialize(using = Params.Serializer::class) + class Params + private constructor( + private val openaiModel: OpenAIModelParams? = null, + private val anthropicModel: AnthropicModelParams? = null, + private val googleModel: GoogleModelParams? = null, + private val windowAiModel: WindowAiModelParams? = null, + private val jsCompletion: JsCompletionParams? = null, + private val _json: JsonValue? = null, + ) { + + fun openaiModel(): OpenAIModelParams? = openaiModel + + fun anthropicModel(): AnthropicModelParams? = anthropicModel + + fun googleModel(): GoogleModelParams? = googleModel + + fun windowAiModel(): WindowAiModelParams? = windowAiModel + + fun jsCompletion(): JsCompletionParams? = jsCompletion + + fun isOpenAIModel(): Boolean = openaiModel != null + + fun isAnthropicModel(): Boolean = anthropicModel != null + + fun isGoogleModel(): Boolean = googleModel != null + + fun isWindowAiModel(): Boolean = windowAiModel != null + + fun isJsCompletion(): Boolean = jsCompletion != null + + fun asOpenAIModel(): OpenAIModelParams = openaiModel.getOrThrow("openaiModel") + + fun asAnthropicModel(): AnthropicModelParams = anthropicModel.getOrThrow("anthropicModel") + + fun asGoogleModel(): GoogleModelParams = googleModel.getOrThrow("googleModel") + + fun asWindowAiModel(): WindowAiModelParams = windowAiModel.getOrThrow("windowAiModel") + + fun asJsCompletion(): JsCompletionParams = jsCompletion.getOrThrow("jsCompletion") + + fun _json(): JsonValue? = _json + + fun accept(visitor: Visitor): T = + when { + openaiModel != null -> visitor.visitOpenAIModel(openaiModel) + anthropicModel != null -> visitor.visitAnthropicModel(anthropicModel) + googleModel != null -> visitor.visitGoogleModel(googleModel) + windowAiModel != null -> visitor.visitWindowAiModel(windowAiModel) + jsCompletion != null -> visitor.visitJsCompletion(jsCompletion) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Params = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitOpenAIModel(openaiModel: OpenAIModelParams) { + openaiModel.validate() + } + + override fun visitAnthropicModel(anthropicModel: AnthropicModelParams) { + anthropicModel.validate() + } + + override fun visitGoogleModel(googleModel: GoogleModelParams) { + googleModel.validate() + } + + override fun visitWindowAiModel(windowAiModel: WindowAiModelParams) { + windowAiModel.validate() + } + + override fun visitJsCompletion(jsCompletion: JsCompletionParams) { + jsCompletion.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitOpenAIModel(openaiModel: OpenAIModelParams) = + openaiModel.validity() + + override fun visitAnthropicModel(anthropicModel: AnthropicModelParams) = + anthropicModel.validity() + + override fun visitGoogleModel(googleModel: GoogleModelParams) = + googleModel.validity() + + override fun visitWindowAiModel(windowAiModel: WindowAiModelParams) = + windowAiModel.validity() + + override fun visitJsCompletion(jsCompletion: JsCompletionParams) = + jsCompletion.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Params && + openaiModel == other.openaiModel && + anthropicModel == other.anthropicModel && + googleModel == other.googleModel && + windowAiModel == other.windowAiModel && + jsCompletion == other.jsCompletion + } + + override fun hashCode(): Int = + Objects.hash(openaiModel, anthropicModel, googleModel, windowAiModel, jsCompletion) + + override fun toString(): String = + when { + openaiModel != null -> "Params{openaiModel=$openaiModel}" + anthropicModel != null -> "Params{anthropicModel=$anthropicModel}" + googleModel != null -> "Params{googleModel=$googleModel}" + windowAiModel != null -> "Params{windowAiModel=$windowAiModel}" + jsCompletion != null -> "Params{jsCompletion=$jsCompletion}" + _json != null -> "Params{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Params") + } + + companion object { + + fun ofOpenAIModel(openaiModel: OpenAIModelParams) = Params(openaiModel = openaiModel) + + fun ofAnthropicModel(anthropicModel: AnthropicModelParams) = + Params(anthropicModel = anthropicModel) + + fun ofGoogleModel(googleModel: GoogleModelParams) = Params(googleModel = googleModel) + + fun ofWindowAiModel(windowAiModel: WindowAiModelParams) = + Params(windowAiModel = windowAiModel) + + fun ofJsCompletion(jsCompletion: JsCompletionParams) = + Params(jsCompletion = jsCompletion) + } + + /** An interface that defines how to map each variant of [Params] to a value of type [T]. */ + interface Visitor { + + fun visitOpenAIModel(openaiModel: OpenAIModelParams): T + + fun visitAnthropicModel(anthropicModel: AnthropicModelParams): T + + fun visitGoogleModel(googleModel: GoogleModelParams): T + + fun visitWindowAiModel(windowAiModel: WindowAiModelParams): T + + fun visitJsCompletion(jsCompletion: JsCompletionParams): T + + /** + * Maps an unknown variant of [Params] to a value of type [T]. + * + * An instance of [Params] 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 BraintrustInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("Unknown Params: $json") + } + } + + internal class Deserializer : BaseDeserializer(Params::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Params { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Params(openaiModel = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Params(anthropicModel = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Params(googleModel = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Params(windowAiModel = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Params(jsCompletion = 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 -> Params(_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(Params::class) { + + override fun serialize( + value: Params, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.openaiModel != null -> generator.writeObject(value.openaiModel) + value.anthropicModel != null -> generator.writeObject(value.anthropicModel) + value.googleModel != null -> generator.writeObject(value.googleModel) + value.windowAiModel != null -> generator.writeObject(value.windowAiModel) + value.jsCompletion != null -> generator.writeObject(value.jsCompletion) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Params") + } + } + } + + class OpenAIModelParams + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val frequencyPenalty: JsonField, + private val functionCall: JsonField, + private val maxCompletionTokens: JsonField, + private val maxTokens: JsonField, + private val n: JsonField, + private val presencePenalty: JsonField, + private val reasoningEffort: JsonField, + private val responseFormat: JsonField, + private val stop: JsonField>, + private val temperature: JsonField, + private val toolChoice: JsonField, + private val topP: JsonField, + private val useCache: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("frequency_penalty") + @ExcludeMissing + frequencyPenalty: JsonField = JsonMissing.of(), + @JsonProperty("function_call") + @ExcludeMissing + functionCall: JsonField = JsonMissing.of(), + @JsonProperty("max_completion_tokens") + @ExcludeMissing + maxCompletionTokens: JsonField = JsonMissing.of(), + @JsonProperty("max_tokens") + @ExcludeMissing + maxTokens: JsonField = JsonMissing.of(), + @JsonProperty("n") @ExcludeMissing n: JsonField = JsonMissing.of(), + @JsonProperty("presence_penalty") + @ExcludeMissing + presencePenalty: JsonField = JsonMissing.of(), + @JsonProperty("reasoning_effort") + @ExcludeMissing + reasoningEffort: JsonField = JsonMissing.of(), + @JsonProperty("response_format") + @ExcludeMissing + responseFormat: JsonField = JsonMissing.of(), + @JsonProperty("stop") + @ExcludeMissing + stop: JsonField> = JsonMissing.of(), + @JsonProperty("temperature") + @ExcludeMissing + temperature: JsonField = JsonMissing.of(), + @JsonProperty("tool_choice") + @ExcludeMissing + toolChoice: JsonField = JsonMissing.of(), + @JsonProperty("top_p") @ExcludeMissing topP: JsonField = JsonMissing.of(), + @JsonProperty("use_cache") + @ExcludeMissing + useCache: JsonField = JsonMissing.of(), + ) : this( + frequencyPenalty, + functionCall, + maxCompletionTokens, + maxTokens, + n, + presencePenalty, + reasoningEffort, + responseFormat, + stop, + temperature, + toolChoice, + topP, + useCache, + mutableMapOf(), + ) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun frequencyPenalty(): Double? = frequencyPenalty.getNullable("frequency_penalty") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun functionCall(): FunctionCall? = functionCall.getNullable("function_call") + + /** + * The successor to max_tokens + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun maxCompletionTokens(): Double? = + maxCompletionTokens.getNullable("max_completion_tokens") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun maxTokens(): Double? = maxTokens.getNullable("max_tokens") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun n(): Double? = n.getNullable("n") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun presencePenalty(): Double? = presencePenalty.getNullable("presence_penalty") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun reasoningEffort(): ReasoningEffort? = + reasoningEffort.getNullable("reasoning_effort") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun responseFormat(): ResponseFormat? = responseFormat.getNullable("response_format") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun stop(): List? = stop.getNullable("stop") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun temperature(): Double? = temperature.getNullable("temperature") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun toolChoice(): ToolChoice? = toolChoice.getNullable("tool_choice") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun topP(): Double? = topP.getNullable("top_p") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun useCache(): Boolean? = useCache.getNullable("use_cache") + + /** + * Returns the raw JSON value of [frequencyPenalty]. + * + * Unlike [frequencyPenalty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("frequency_penalty") + @ExcludeMissing + fun _frequencyPenalty(): JsonField = frequencyPenalty + + /** + * Returns the raw JSON value of [functionCall]. + * + * Unlike [functionCall], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_call") + @ExcludeMissing + fun _functionCall(): JsonField = functionCall + + /** + * Returns the raw JSON value of [maxCompletionTokens]. + * + * Unlike [maxCompletionTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("max_completion_tokens") + @ExcludeMissing + fun _maxCompletionTokens(): JsonField = maxCompletionTokens + + /** + * Returns the raw JSON value of [maxTokens]. + * + * Unlike [maxTokens], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("max_tokens") + @ExcludeMissing + fun _maxTokens(): JsonField = maxTokens + + /** + * Returns the raw JSON value of [n]. + * + * Unlike [n], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("n") @ExcludeMissing fun _n(): JsonField = n + + /** + * Returns the raw JSON value of [presencePenalty]. + * + * Unlike [presencePenalty], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("presence_penalty") + @ExcludeMissing + fun _presencePenalty(): JsonField = presencePenalty + + /** + * Returns the raw JSON value of [reasoningEffort]. + * + * Unlike [reasoningEffort], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("reasoning_effort") + @ExcludeMissing + fun _reasoningEffort(): JsonField = reasoningEffort + + /** + * Returns the raw JSON value of [responseFormat]. + * + * Unlike [responseFormat], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("response_format") + @ExcludeMissing + fun _responseFormat(): JsonField = responseFormat + + /** + * Returns the raw JSON value of [stop]. + * + * Unlike [stop], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("stop") @ExcludeMissing fun _stop(): JsonField> = stop + + /** + * Returns the raw JSON value of [temperature]. + * + * Unlike [temperature], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("temperature") + @ExcludeMissing + fun _temperature(): JsonField = temperature + + /** + * Returns the raw JSON value of [toolChoice]. + * + * Unlike [toolChoice], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("tool_choice") + @ExcludeMissing + fun _toolChoice(): JsonField = toolChoice + + /** + * Returns the raw JSON value of [topP]. + * + * Unlike [topP], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("top_p") @ExcludeMissing fun _topP(): JsonField = topP + + /** + * Returns the raw JSON value of [useCache]. + * + * Unlike [useCache], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("use_cache") + @ExcludeMissing + fun _useCache(): JsonField = useCache + + @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 [OpenAIModelParams]. + */ + fun builder() = Builder() + } + + /** A builder for [OpenAIModelParams]. */ + class Builder internal constructor() { + + private var frequencyPenalty: JsonField = JsonMissing.of() + private var functionCall: JsonField = JsonMissing.of() + private var maxCompletionTokens: JsonField = JsonMissing.of() + private var maxTokens: JsonField = JsonMissing.of() + private var n: JsonField = JsonMissing.of() + private var presencePenalty: JsonField = JsonMissing.of() + private var reasoningEffort: JsonField = JsonMissing.of() + private var responseFormat: JsonField = JsonMissing.of() + private var stop: JsonField>? = null + private var temperature: JsonField = JsonMissing.of() + private var toolChoice: JsonField = JsonMissing.of() + private var topP: JsonField = JsonMissing.of() + private var useCache: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(openaiModelParams: OpenAIModelParams) = apply { + frequencyPenalty = openaiModelParams.frequencyPenalty + functionCall = openaiModelParams.functionCall + maxCompletionTokens = openaiModelParams.maxCompletionTokens + maxTokens = openaiModelParams.maxTokens + n = openaiModelParams.n + presencePenalty = openaiModelParams.presencePenalty + reasoningEffort = openaiModelParams.reasoningEffort + responseFormat = openaiModelParams.responseFormat + stop = openaiModelParams.stop.map { it.toMutableList() } + temperature = openaiModelParams.temperature + toolChoice = openaiModelParams.toolChoice + topP = openaiModelParams.topP + useCache = openaiModelParams.useCache + additionalProperties = openaiModelParams.additionalProperties.toMutableMap() + } + + fun frequencyPenalty(frequencyPenalty: Double) = + frequencyPenalty(JsonField.of(frequencyPenalty)) + + /** + * Sets [Builder.frequencyPenalty] to an arbitrary JSON value. + * + * You should usually call [Builder.frequencyPenalty] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun frequencyPenalty(frequencyPenalty: JsonField) = apply { + this.frequencyPenalty = frequencyPenalty + } + + fun functionCall(functionCall: FunctionCall) = + functionCall(JsonField.of(functionCall)) + + /** + * Sets [Builder.functionCall] to an arbitrary JSON value. + * + * You should usually call [Builder.functionCall] with a well-typed [FunctionCall] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun functionCall(functionCall: JsonField) = apply { + this.functionCall = functionCall + } + + /** + * Alias for calling [functionCall] with + * `FunctionCall.ofUnionMember0(unionMember0)`. + */ + fun functionCall(unionMember0: FunctionCall.UnionMember0) = + functionCall(FunctionCall.ofUnionMember0(unionMember0)) + + /** Alias for calling [functionCall] with `FunctionCall.ofFunction(function)`. */ + fun functionCall(function: FunctionCall.Function) = + functionCall(FunctionCall.ofFunction(function)) + + /** The successor to max_tokens */ + fun maxCompletionTokens(maxCompletionTokens: Double) = + maxCompletionTokens(JsonField.of(maxCompletionTokens)) + + /** + * Sets [Builder.maxCompletionTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.maxCompletionTokens] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun maxCompletionTokens(maxCompletionTokens: JsonField) = apply { + this.maxCompletionTokens = maxCompletionTokens + } + + fun maxTokens(maxTokens: Double) = maxTokens(JsonField.of(maxTokens)) + + /** + * Sets [Builder.maxTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.maxTokens] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun maxTokens(maxTokens: JsonField) = apply { this.maxTokens = maxTokens } + + fun n(n: Double) = n(JsonField.of(n)) + + /** + * Sets [Builder.n] to an arbitrary JSON value. + * + * You should usually call [Builder.n] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun n(n: JsonField) = apply { this.n = n } + + fun presencePenalty(presencePenalty: Double) = + presencePenalty(JsonField.of(presencePenalty)) + + /** + * Sets [Builder.presencePenalty] to an arbitrary JSON value. + * + * You should usually call [Builder.presencePenalty] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun presencePenalty(presencePenalty: JsonField) = apply { + this.presencePenalty = presencePenalty + } + + fun reasoningEffort(reasoningEffort: ReasoningEffort) = + reasoningEffort(JsonField.of(reasoningEffort)) + + /** + * Sets [Builder.reasoningEffort] to an arbitrary JSON value. + * + * You should usually call [Builder.reasoningEffort] with a well-typed + * [ReasoningEffort] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun reasoningEffort(reasoningEffort: JsonField) = apply { + this.reasoningEffort = reasoningEffort + } + + fun responseFormat(responseFormat: ResponseFormat?) = + responseFormat(JsonField.ofNullable(responseFormat)) + + /** + * Sets [Builder.responseFormat] to an arbitrary JSON value. + * + * You should usually call [Builder.responseFormat] with a well-typed + * [ResponseFormat] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun responseFormat(responseFormat: JsonField) = apply { + this.responseFormat = responseFormat + } + + /** + * Alias for calling [responseFormat] with + * `ResponseFormat.ofJsonObject(jsonObject)`. + */ + fun responseFormat(jsonObject: ResponseFormat.JsonObject) = + responseFormat(ResponseFormat.ofJsonObject(jsonObject)) + + /** + * Alias for calling [responseFormat] with + * `ResponseFormat.ofJsonSchema(jsonSchema)`. + */ + fun responseFormat(jsonSchema: ResponseFormat.JsonSchema) = + responseFormat(ResponseFormat.ofJsonSchema(jsonSchema)) + + /** Alias for calling [responseFormat] with `ResponseFormat.ofText(text)`. */ + fun responseFormat(text: ResponseFormat.Text) = + responseFormat(ResponseFormat.ofText(text)) + + fun stop(stop: List) = stop(JsonField.of(stop)) + + /** + * Sets [Builder.stop] to an arbitrary JSON value. + * + * You should usually call [Builder.stop] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun stop(stop: JsonField>) = apply { + this.stop = stop.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [Builder.stop]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addStop(stop: String) = apply { + this.stop = + (this.stop ?: JsonField.of(mutableListOf())).also { + checkKnown("stop", it).add(stop) + } + } + + fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) + + /** + * Sets [Builder.temperature] to an arbitrary JSON value. + * + * You should usually call [Builder.temperature] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun temperature(temperature: JsonField) = apply { + this.temperature = temperature + } + + fun toolChoice(toolChoice: ToolChoice) = toolChoice(JsonField.of(toolChoice)) + + /** + * Sets [Builder.toolChoice] to an arbitrary JSON value. + * + * You should usually call [Builder.toolChoice] with a well-typed [ToolChoice] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun toolChoice(toolChoice: JsonField) = apply { + this.toolChoice = toolChoice + } + + /** + * Alias for calling [toolChoice] with `ToolChoice.ofUnionMember0(unionMember0)`. + */ + fun toolChoice(unionMember0: ToolChoice.UnionMember0) = + toolChoice(ToolChoice.ofUnionMember0(unionMember0)) + + /** Alias for calling [toolChoice] with `ToolChoice.ofFunction(function)`. */ + fun toolChoice(function: ToolChoice.Function) = + toolChoice(ToolChoice.ofFunction(function)) + + fun topP(topP: Double) = topP(JsonField.of(topP)) + + /** + * Sets [Builder.topP] to an arbitrary JSON value. + * + * You should usually call [Builder.topP] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun topP(topP: JsonField) = apply { this.topP = topP } + + fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) + + /** + * Sets [Builder.useCache] to an arbitrary JSON value. + * + * You should usually call [Builder.useCache] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun useCache(useCache: JsonField) = apply { this.useCache = useCache } + + 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 [OpenAIModelParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): OpenAIModelParams = + OpenAIModelParams( + frequencyPenalty, + functionCall, + maxCompletionTokens, + maxTokens, + n, + presencePenalty, + reasoningEffort, + responseFormat, + (stop ?: JsonMissing.of()).map { it.toImmutable() }, + temperature, + toolChoice, + topP, + useCache, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): OpenAIModelParams = apply { + if (validated) { + return@apply + } + + frequencyPenalty() + functionCall()?.validate() + maxCompletionTokens() + maxTokens() + n() + presencePenalty() + reasoningEffort()?.validate() + responseFormat()?.validate() + stop() + temperature() + toolChoice()?.validate() + topP() + useCache() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (frequencyPenalty.asKnown() == null) 0 else 1) + + (functionCall.asKnown()?.validity() ?: 0) + + (if (maxCompletionTokens.asKnown() == null) 0 else 1) + + (if (maxTokens.asKnown() == null) 0 else 1) + + (if (n.asKnown() == null) 0 else 1) + + (if (presencePenalty.asKnown() == null) 0 else 1) + + (reasoningEffort.asKnown()?.validity() ?: 0) + + (responseFormat.asKnown()?.validity() ?: 0) + + (stop.asKnown()?.size ?: 0) + + (if (temperature.asKnown() == null) 0 else 1) + + (toolChoice.asKnown()?.validity() ?: 0) + + (if (topP.asKnown() == null) 0 else 1) + + (if (useCache.asKnown() == null) 0 else 1) + + @JsonDeserialize(using = FunctionCall.Deserializer::class) + @JsonSerialize(using = FunctionCall.Serializer::class) + class FunctionCall + private constructor( + private val unionMember0: UnionMember0? = null, + private val function: Function? = null, + private val _json: JsonValue? = null, + ) { + + fun unionMember0(): UnionMember0? = unionMember0 + + fun function(): Function? = function + + fun isUnionMember0(): Boolean = unionMember0 != null + + fun isFunction(): Boolean = function != null + + fun asUnionMember0(): UnionMember0 = unionMember0.getOrThrow("unionMember0") + + fun asFunction(): Function = function.getOrThrow("function") + + fun _json(): JsonValue? = _json + + fun accept(visitor: Visitor): T = + when { + unionMember0 != null -> visitor.visitUnionMember0(unionMember0) + function != null -> visitor.visitFunction(function) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): FunctionCall = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitUnionMember0(unionMember0: UnionMember0) { + unionMember0.validate() + } + + override fun visitFunction(function: Function) { + function.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitUnionMember0(unionMember0: UnionMember0) = + unionMember0.validity() + + override fun visitFunction(function: Function) = function.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FunctionCall && + unionMember0 == other.unionMember0 && + function == other.function + } + + override fun hashCode(): Int = Objects.hash(unionMember0, function) + + override fun toString(): String = + when { + unionMember0 != null -> "FunctionCall{unionMember0=$unionMember0}" + function != null -> "FunctionCall{function=$function}" + _json != null -> "FunctionCall{_unknown=$_json}" + else -> throw IllegalStateException("Invalid FunctionCall") + } + + companion object { + + fun ofUnionMember0(unionMember0: UnionMember0) = + FunctionCall(unionMember0 = unionMember0) + + fun ofFunction(function: Function) = FunctionCall(function = function) + } + + /** + * An interface that defines how to map each variant of [FunctionCall] to a value of + * type [T]. + */ + interface Visitor { + + fun visitUnionMember0(unionMember0: UnionMember0): T + + fun visitFunction(function: Function): T + + /** + * Maps an unknown variant of [FunctionCall] to a value of type [T]. + * + * An instance of [FunctionCall] 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 BraintrustInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("Unknown FunctionCall: $json") + } + } + + internal class Deserializer : BaseDeserializer(FunctionCall::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): FunctionCall { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionCall(unionMember0 = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + FunctionCall(function = 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 -> FunctionCall(_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(FunctionCall::class) { + + override fun serialize( + value: FunctionCall, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.unionMember0 != null -> generator.writeObject(value.unionMember0) + value.function != null -> generator.writeObject(value.function) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid FunctionCall") + } + } + } + + class UnionMember0 + @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 { + + val AUTO = of("auto") + + val NONE = of("none") + + fun of(value: String) = UnionMember0(JsonField.of(value)) + } + + /** An enum containing [UnionMember0]'s known values. */ + enum class Known { + AUTO, + NONE, + } + + /** + * An enum containing [UnionMember0]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [UnionMember0] 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 { + AUTO, + NONE, + /** + * An enum member indicating that [UnionMember0] 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) { + AUTO -> Value.AUTO + NONE -> Value.NONE + 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 BraintrustInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + AUTO -> Known.AUTO + NONE -> Known.NONE + else -> + throw BraintrustInvalidDataException("Unknown UnionMember0: $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 BraintrustInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): UnionMember0 = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 UnionMember0 && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of() + ) : this(name, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @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 [Function]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [Function]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(function: Function) = apply { + name = function.name + additionalProperties = function.additionalProperties.toMutableMap() + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Function = + Function( + checkRequired("name", name), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Function = apply { + if (validated) { + return@apply + } + + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (name.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Function && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Function{name=$name, additionalProperties=$additionalProperties}" + } + } + + class ReasoningEffort + @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 { + + val LOW = of("low") + + val MEDIUM = of("medium") + + val HIGH = of("high") + + fun of(value: String) = ReasoningEffort(JsonField.of(value)) + } + + /** An enum containing [ReasoningEffort]'s known values. */ + enum class Known { + LOW, + MEDIUM, + HIGH, + } + + /** + * An enum containing [ReasoningEffort]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [ReasoningEffort] 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 { + LOW, + MEDIUM, + HIGH, + /** + * An enum member indicating that [ReasoningEffort] 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) { + LOW -> Value.LOW + MEDIUM -> Value.MEDIUM + HIGH -> Value.HIGH + 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 BraintrustInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + LOW -> Known.LOW + MEDIUM -> Known.MEDIUM + HIGH -> Known.HIGH + else -> + throw BraintrustInvalidDataException("Unknown ReasoningEffort: $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 BraintrustInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ReasoningEffort = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ReasoningEffort && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + @JsonDeserialize(using = ResponseFormat.Deserializer::class) + @JsonSerialize(using = ResponseFormat.Serializer::class) + class ResponseFormat + private constructor( + private val jsonObject: JsonObject? = null, + private val jsonSchema: JsonSchema? = null, + private val text: Text? = null, + private val _json: JsonValue? = null, + ) { + + fun jsonObject(): JsonObject? = jsonObject + + fun jsonSchema(): JsonSchema? = jsonSchema + + fun text(): Text? = text + + fun isJsonObject(): Boolean = jsonObject != null + + fun isJsonSchema(): Boolean = jsonSchema != null + + fun isText(): Boolean = text != null + + fun asJsonObject(): JsonObject = jsonObject.getOrThrow("jsonObject") + + fun asJsonSchema(): JsonSchema = jsonSchema.getOrThrow("jsonSchema") + + fun asText(): Text = text.getOrThrow("text") + + fun _json(): JsonValue? = _json + + fun accept(visitor: Visitor): T = + when { + jsonObject != null -> visitor.visitJsonObject(jsonObject) + jsonSchema != null -> visitor.visitJsonSchema(jsonSchema) + text != null -> visitor.visitText(text) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ResponseFormat = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitJsonObject(jsonObject: JsonObject) { + jsonObject.validate() + } + + override fun visitJsonSchema(jsonSchema: JsonSchema) { + jsonSchema.validate() + } + + override fun visitText(text: Text) { + text.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitJsonObject(jsonObject: JsonObject) = + jsonObject.validity() + + override fun visitJsonSchema(jsonSchema: JsonSchema) = + jsonSchema.validity() + + override fun visitText(text: Text) = text.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ResponseFormat && + jsonObject == other.jsonObject && + jsonSchema == other.jsonSchema && + text == other.text + } + + override fun hashCode(): Int = Objects.hash(jsonObject, jsonSchema, text) + + override fun toString(): String = + when { + jsonObject != null -> "ResponseFormat{jsonObject=$jsonObject}" + jsonSchema != null -> "ResponseFormat{jsonSchema=$jsonSchema}" + text != null -> "ResponseFormat{text=$text}" + _json != null -> "ResponseFormat{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ResponseFormat") + } + + companion object { + + fun ofJsonObject(jsonObject: JsonObject) = + ResponseFormat(jsonObject = jsonObject) + + fun ofJsonSchema(jsonSchema: JsonSchema) = + ResponseFormat(jsonSchema = jsonSchema) + + fun ofText(text: Text) = ResponseFormat(text = text) + } + + /** + * An interface that defines how to map each variant of [ResponseFormat] to a value + * of type [T]. + */ + interface Visitor { + + fun visitJsonObject(jsonObject: JsonObject): T + + fun visitJsonSchema(jsonSchema: JsonSchema): T + + fun visitText(text: Text): T + + /** + * Maps an unknown variant of [ResponseFormat] to a value of type [T]. + * + * An instance of [ResponseFormat] 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 BraintrustInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("Unknown ResponseFormat: $json") + } + } + + internal class Deserializer : + BaseDeserializer(ResponseFormat::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ResponseFormat { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + ResponseFormat(jsonObject = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ResponseFormat(jsonSchema = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ResponseFormat(text = 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 -> ResponseFormat(_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(ResponseFormat::class) { + + override fun serialize( + value: ResponseFormat, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.jsonObject != null -> generator.writeObject(value.jsonObject) + value.jsonSchema != null -> generator.writeObject(value.jsonSchema) + value.text != null -> generator.writeObject(value.text) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ResponseFormat") + } + } + } + + class JsonObject + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of() + ) : this(type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 [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 [JsonObject]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [JsonObject]. */ + class Builder internal constructor() { + + private var type: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(jsonObject: JsonObject) = apply { + type = jsonObject.type + additionalProperties = jsonObject.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 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 [JsonObject]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): JsonObject = + JsonObject( + checkRequired("type", type), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): JsonObject = apply { + if (validated) { + return@apply + } + + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (type.asKnown()?.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 { + + val JSON_OBJECT = of("json_object") + + fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + JSON_OBJECT + } + + /** + * 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 { + JSON_OBJECT, + /** + * 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) { + JSON_OBJECT -> Value.JSON_OBJECT + 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + JSON_OBJECT -> Known.JSON_OBJECT + else -> throw BraintrustInvalidDataException("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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 JsonObject && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "JsonObject{type=$type, additionalProperties=$additionalProperties}" + } + + class JsonSchema + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val jsonSchema: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("json_schema") + @ExcludeMissing + jsonSchema: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(jsonSchema, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 jsonSchema(): InnerJsonSchema = jsonSchema.getRequired("json_schema") + + /** + * @throws BraintrustInvalidDataException 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 [jsonSchema]. + * + * Unlike [jsonSchema], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("json_schema") + @ExcludeMissing + fun _jsonSchema(): JsonField = jsonSchema + + /** + * 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 [JsonSchema]. + * + * The following fields are required: + * ```kotlin + * .jsonSchema() + * .type() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [JsonSchema]. */ + class Builder internal constructor() { + + private var jsonSchema: JsonField? = null + private var type: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(jsonSchema: JsonSchema) = apply { + this.jsonSchema = jsonSchema.jsonSchema + type = jsonSchema.type + additionalProperties = jsonSchema.additionalProperties.toMutableMap() + } + + fun jsonSchema(jsonSchema: InnerJsonSchema) = + jsonSchema(JsonField.of(jsonSchema)) + + /** + * Sets [Builder.jsonSchema] to an arbitrary JSON value. + * + * You should usually call [Builder.jsonSchema] with a well-typed + * [InnerJsonSchema] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun jsonSchema(jsonSchema: JsonField) = apply { + this.jsonSchema = jsonSchema + } + + 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 [JsonSchema]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .jsonSchema() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): JsonSchema = + JsonSchema( + checkRequired("jsonSchema", jsonSchema), + checkRequired("type", type), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): JsonSchema = apply { + if (validated) { + return@apply + } + + jsonSchema().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (jsonSchema.asKnown()?.validity() ?: 0) + (type.asKnown()?.validity() ?: 0) + + class InnerJsonSchema + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val description: JsonField, + private val schema: JsonField, + private val strict: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("schema") + @ExcludeMissing + schema: JsonField = JsonMissing.of(), + @JsonProperty("strict") + @ExcludeMissing + strict: JsonField = JsonMissing.of(), + ) : this(name, description, schema, strict, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun description(): String? = description.getNullable("description") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun schema(): Schema? = schema.getNullable("schema") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun strict(): Boolean? = strict.getNullable("strict") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [schema]. + * + * Unlike [schema], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("schema") + @ExcludeMissing + fun _schema(): JsonField = schema + + /** + * Returns the raw JSON value of [strict]. + * + * Unlike [strict], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("strict") + @ExcludeMissing + fun _strict(): JsonField = strict + + @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 + * [InnerJsonSchema]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [InnerJsonSchema]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var schema: JsonField = JsonMissing.of() + private var strict: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(innerJsonSchema: InnerJsonSchema) = apply { + name = innerJsonSchema.name + description = innerJsonSchema.description + schema = innerJsonSchema.schema + strict = innerJsonSchema.strict + additionalProperties = + innerJsonSchema.additionalProperties.toMutableMap() + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 + } + + 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 } + + /** Alias for calling [schema] with `Schema.ofObject(object_)`. */ + fun schema(object_: Schema.Object) = schema(Schema.ofObject(object_)) + + /** Alias for calling [schema] with `Schema.ofString(string)`. */ + fun schema(string: String) = schema(Schema.ofString(string)) + + fun strict(strict: Boolean?) = strict(JsonField.ofNullable(strict)) + + /** + * Alias for [Builder.strict]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun strict(strict: Boolean) = strict(strict as Boolean?) + + /** + * Sets [Builder.strict] to an arbitrary JSON value. + * + * You should usually call [Builder.strict] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun strict(strict: JsonField) = apply { this.strict = strict } + + 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 [InnerJsonSchema]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): InnerJsonSchema = + InnerJsonSchema( + checkRequired("name", name), + description, + schema, + strict, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): InnerJsonSchema = apply { + if (validated) { + return@apply + } + + name() + description() + schema()?.validate() + strict() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (schema.asKnown()?.validity() ?: 0) + + (if (strict.asKnown() == null) 0 else 1) + + @JsonDeserialize(using = Schema.Deserializer::class) + @JsonSerialize(using = Schema.Serializer::class) + class Schema + private constructor( + private val object_: Object? = null, + private val string: String? = null, + private val _json: JsonValue? = null, + ) { + + fun object_(): Object? = object_ + + fun string(): String? = string + + fun isObject(): Boolean = object_ != null + + fun isString(): Boolean = string != null + + fun asObject(): Object = object_.getOrThrow("object_") + + fun asString(): String = string.getOrThrow("string") + + fun _json(): JsonValue? = _json + + fun accept(visitor: Visitor): T = + when { + object_ != null -> visitor.visitObject(object_) + string != null -> visitor.visitString(string) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Schema = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitObject(object_: Object) { + object_.validate() + } + + override fun visitString(string: String) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitObject(object_: Object) = + object_.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 Schema && + object_ == other.object_ && + string == other.string + } + + override fun hashCode(): Int = Objects.hash(object_, string) + + override fun toString(): String = + when { + object_ != null -> "Schema{object_=$object_}" + string != null -> "Schema{string=$string}" + _json != null -> "Schema{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Schema") + } + + companion object { + + fun ofObject(object_: Object) = Schema(object_ = object_) + + fun ofString(string: String) = Schema(string = string) + } + + /** + * An interface that defines how to map each variant of [Schema] to a + * value of type [T]. + */ + interface Visitor { + + fun visitObject(object_: Object): T + + fun visitString(string: String): T + + /** + * Maps an unknown variant of [Schema] to a value of type [T]. + * + * An instance of [Schema] 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 BraintrustInvalidDataException in the default + * implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("Unknown Schema: $json") + } + } + + internal class Deserializer : BaseDeserializer(Schema::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Schema { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { Schema(object_ = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef()) + ?.let { Schema(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 -> Schema(_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(Schema::class) { + + override fun serialize( + value: Schema, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.object_ != null -> + generator.writeObject(value.object_) + value.string != null -> generator.writeObject(value.string) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Schema") + } + } + } + + class Object + @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 + * [Object]. + */ + fun builder() = Builder() + } + + /** A builder for [Object]. */ + class Builder internal constructor() { + + private var additionalProperties: + MutableMap = + mutableMapOf() + + internal fun from(object_: Object) = apply { + additionalProperties = + object_.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 [Object]. + * + * Further updates to this [Builder] will not mutate the + * returned instance. + */ + fun build(): Object = Object(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Object = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + 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 Object && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Object{additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InnerJsonSchema && + name == other.name && + description == other.description && + schema == other.schema && + strict == other.strict && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(name, description, schema, strict, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InnerJsonSchema{name=$name, description=$description, schema=$schema, strict=$strict, additionalProperties=$additionalProperties}" + } + + 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 { + + val JSON_SCHEMA = of("json_schema") + + fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + JSON_SCHEMA + } + + /** + * 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 { + JSON_SCHEMA, + /** + * 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) { + JSON_SCHEMA -> Value.JSON_SCHEMA + 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + JSON_SCHEMA -> Known.JSON_SCHEMA + else -> throw BraintrustInvalidDataException("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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 JsonSchema && + jsonSchema == other.jsonSchema && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(jsonSchema, type, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "JsonSchema{jsonSchema=$jsonSchema, type=$type, additionalProperties=$additionalProperties}" + } + + class Text + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of() + ) : this(type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 [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 [Text]. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [Text]. */ + class Builder internal constructor() { + + private var type: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(text: Text) = apply { + type = text.type + additionalProperties = text.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 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 [Text]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Text = + Text(checkRequired("type", type), additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Text = apply { + if (validated) { + return@apply + } + + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (type.asKnown()?.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 { + + val TEXT = of("text") + + fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + TEXT + } + + /** + * 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 { + TEXT, + /** + * 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) { + TEXT -> Value.TEXT + 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + TEXT -> Known.TEXT + else -> throw BraintrustInvalidDataException("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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Text && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Text{type=$type, additionalProperties=$additionalProperties}" + } + } + + @JsonDeserialize(using = ToolChoice.Deserializer::class) + @JsonSerialize(using = ToolChoice.Serializer::class) + class ToolChoice + private constructor( + private val unionMember0: UnionMember0? = null, + private val function: Function? = null, + private val _json: JsonValue? = null, + ) { + + fun unionMember0(): UnionMember0? = unionMember0 + + fun function(): Function? = function + + fun isUnionMember0(): Boolean = unionMember0 != null + + fun isFunction(): Boolean = function != null + + fun asUnionMember0(): UnionMember0 = unionMember0.getOrThrow("unionMember0") + + fun asFunction(): Function = function.getOrThrow("function") + + fun _json(): JsonValue? = _json + + fun accept(visitor: Visitor): T = + when { + unionMember0 != null -> visitor.visitUnionMember0(unionMember0) + function != null -> visitor.visitFunction(function) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ToolChoice = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitUnionMember0(unionMember0: UnionMember0) { + unionMember0.validate() + } + + override fun visitFunction(function: Function) { + function.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitUnionMember0(unionMember0: UnionMember0) = + unionMember0.validity() + + override fun visitFunction(function: Function) = function.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ToolChoice && + unionMember0 == other.unionMember0 && + function == other.function + } + + override fun hashCode(): Int = Objects.hash(unionMember0, function) + + override fun toString(): String = + when { + unionMember0 != null -> "ToolChoice{unionMember0=$unionMember0}" + function != null -> "ToolChoice{function=$function}" + _json != null -> "ToolChoice{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ToolChoice") + } + + companion object { + + fun ofUnionMember0(unionMember0: UnionMember0) = + ToolChoice(unionMember0 = unionMember0) + + fun ofFunction(function: Function) = ToolChoice(function = function) + } + + /** + * An interface that defines how to map each variant of [ToolChoice] to a value of + * type [T]. + */ + interface Visitor { + + fun visitUnionMember0(unionMember0: UnionMember0): T + + fun visitFunction(function: Function): T + + /** + * Maps an unknown variant of [ToolChoice] to a value of type [T]. + * + * An instance of [ToolChoice] 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 BraintrustInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw BraintrustInvalidDataException("Unknown ToolChoice: $json") + } + } + + internal class Deserializer : BaseDeserializer(ToolChoice::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ToolChoice { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + ToolChoice(unionMember0 = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ToolChoice(function = 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 -> ToolChoice(_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(ToolChoice::class) { + + override fun serialize( + value: ToolChoice, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.unionMember0 != null -> generator.writeObject(value.unionMember0) + value.function != null -> generator.writeObject(value.function) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ToolChoice") + } + } + } + + class UnionMember0 + @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 { + + val AUTO = of("auto") + + val NONE = of("none") + + val REQUIRED = of("required") + + fun of(value: String) = UnionMember0(JsonField.of(value)) + } + + /** An enum containing [UnionMember0]'s known values. */ + enum class Known { + AUTO, + NONE, + REQUIRED, + } + + /** + * An enum containing [UnionMember0]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [UnionMember0] 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 { + AUTO, + NONE, + REQUIRED, + /** + * An enum member indicating that [UnionMember0] 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) { + AUTO -> Value.AUTO + NONE -> Value.NONE + REQUIRED -> Value.REQUIRED + 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 BraintrustInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + AUTO -> Known.AUTO + NONE -> Known.NONE + REQUIRED -> Known.REQUIRED + else -> + throw BraintrustInvalidDataException("Unknown UnionMember0: $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 BraintrustInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): UnionMember0 = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 UnionMember0 && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Function + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val function: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("function") + @ExcludeMissing + function: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + ) : this(function, type, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 function(): InnerFunction = function.getRequired("function") + + /** + * @throws BraintrustInvalidDataException 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 [function]. + * + * Unlike [function], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("function") + @ExcludeMissing + fun _function(): JsonField = function + + /** + * 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 [Function]. + * + * The following fields are required: + * ```kotlin + * .function() + * .type() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [Function]. */ + class Builder internal constructor() { + + private var function: JsonField? = null + private var type: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(function: Function) = apply { + this.function = function.function + type = function.type + additionalProperties = function.additionalProperties.toMutableMap() + } + + fun function(function: InnerFunction) = function(JsonField.of(function)) + + /** + * Sets [Builder.function] to an arbitrary JSON value. + * + * You should usually call [Builder.function] with a well-typed + * [InnerFunction] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun function(function: JsonField) = apply { + this.function = function + } + + 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 [Function]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .function() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Function = + Function( + checkRequired("function", function), + checkRequired("type", type), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Function = apply { + if (validated) { + return@apply + } + + function().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (function.asKnown()?.validity() ?: 0) + (type.asKnown()?.validity() ?: 0) + + class InnerFunction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") + @ExcludeMissing + name: JsonField = JsonMissing.of() + ) : this(name, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @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 + * [InnerFunction]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [InnerFunction]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + internal fun from(innerFunction: InnerFunction) = apply { + name = innerFunction.name + additionalProperties = + innerFunction.additionalProperties.toMutableMap() + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + 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 [InnerFunction]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): InnerFunction = + InnerFunction( + checkRequired("name", name), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): InnerFunction = apply { + if (validated) { + return@apply + } + + name() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (name.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is InnerFunction && + name == other.name && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(name, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "InnerFunction{name=$name, additionalProperties=$additionalProperties}" + } + + 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 { + + val FUNCTION = of("function") + + fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + FUNCTION + } + + /** + * 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 { + FUNCTION, + /** + * 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) { + FUNCTION -> Value.FUNCTION + 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 BraintrustInvalidDataException if this class instance's value is + * a not a known member. + */ + fun known(): Known = + when (this) { + FUNCTION -> Known.FUNCTION + else -> throw BraintrustInvalidDataException("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 BraintrustInvalidDataException if this class instance's value + * does not have the expected primitive type. + */ + fun asString(): String = + _value().asString() + ?: throw BraintrustInvalidDataException("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: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + 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 Function && + function == other.function && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(function, type, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Function{function=$function, type=$type, additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is OpenAIModelParams && + frequencyPenalty == other.frequencyPenalty && + functionCall == other.functionCall && + maxCompletionTokens == other.maxCompletionTokens && + maxTokens == other.maxTokens && + n == other.n && + presencePenalty == other.presencePenalty && + reasoningEffort == other.reasoningEffort && + responseFormat == other.responseFormat && + stop == other.stop && + temperature == other.temperature && + toolChoice == other.toolChoice && + topP == other.topP && + useCache == other.useCache && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + frequencyPenalty, + functionCall, + maxCompletionTokens, + maxTokens, + n, + presencePenalty, + reasoningEffort, + responseFormat, + stop, + temperature, + toolChoice, + topP, + useCache, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "OpenAIModelParams{frequencyPenalty=$frequencyPenalty, functionCall=$functionCall, maxCompletionTokens=$maxCompletionTokens, maxTokens=$maxTokens, n=$n, presencePenalty=$presencePenalty, reasoningEffort=$reasoningEffort, responseFormat=$responseFormat, stop=$stop, temperature=$temperature, toolChoice=$toolChoice, topP=$topP, useCache=$useCache, additionalProperties=$additionalProperties}" + } + + class AnthropicModelParams + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val maxTokens: JsonField, + private val temperature: JsonField, + private val maxTokensToSample: JsonField, + private val stopSequences: JsonField>, + private val topK: JsonField, + private val topP: JsonField, + private val useCache: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("max_tokens") + @ExcludeMissing + maxTokens: JsonField = JsonMissing.of(), + @JsonProperty("temperature") + @ExcludeMissing + temperature: JsonField = JsonMissing.of(), + @JsonProperty("max_tokens_to_sample") + @ExcludeMissing + maxTokensToSample: JsonField = JsonMissing.of(), + @JsonProperty("stop_sequences") + @ExcludeMissing + stopSequences: JsonField> = JsonMissing.of(), + @JsonProperty("top_k") @ExcludeMissing topK: JsonField = JsonMissing.of(), + @JsonProperty("top_p") @ExcludeMissing topP: JsonField = JsonMissing.of(), + @JsonProperty("use_cache") + @ExcludeMissing + useCache: JsonField = JsonMissing.of(), + ) : this( + maxTokens, + temperature, + maxTokensToSample, + stopSequences, + topK, + topP, + useCache, + mutableMapOf(), + ) + + /** + * @throws BraintrustInvalidDataException 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 maxTokens(): Double = maxTokens.getRequired("max_tokens") + + /** + * @throws BraintrustInvalidDataException 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 temperature(): Double = temperature.getRequired("temperature") + + /** + * This is a legacy parameter that should not be used. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun maxTokensToSample(): Double? = maxTokensToSample.getNullable("max_tokens_to_sample") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun stopSequences(): List? = stopSequences.getNullable("stop_sequences") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun topK(): Double? = topK.getNullable("top_k") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun topP(): Double? = topP.getNullable("top_p") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun useCache(): Boolean? = useCache.getNullable("use_cache") + + /** + * Returns the raw JSON value of [maxTokens]. + * + * Unlike [maxTokens], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("max_tokens") + @ExcludeMissing + fun _maxTokens(): JsonField = maxTokens + + /** + * Returns the raw JSON value of [temperature]. + * + * Unlike [temperature], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("temperature") + @ExcludeMissing + fun _temperature(): JsonField = temperature + + /** + * Returns the raw JSON value of [maxTokensToSample]. + * + * Unlike [maxTokensToSample], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("max_tokens_to_sample") + @ExcludeMissing + fun _maxTokensToSample(): JsonField = maxTokensToSample + + /** + * Returns the raw JSON value of [stopSequences]. + * + * Unlike [stopSequences], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("stop_sequences") + @ExcludeMissing + fun _stopSequences(): JsonField> = stopSequences + + /** + * Returns the raw JSON value of [topK]. + * + * Unlike [topK], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("top_k") @ExcludeMissing fun _topK(): JsonField = topK + + /** + * Returns the raw JSON value of [topP]. + * + * Unlike [topP], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("top_p") @ExcludeMissing fun _topP(): JsonField = topP + + /** + * Returns the raw JSON value of [useCache]. + * + * Unlike [useCache], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("use_cache") + @ExcludeMissing + fun _useCache(): JsonField = useCache + + @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 [AnthropicModelParams]. + * + * The following fields are required: + * ```kotlin + * .maxTokens() + * .temperature() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [AnthropicModelParams]. */ + class Builder internal constructor() { + + private var maxTokens: JsonField? = null + private var temperature: JsonField? = null + private var maxTokensToSample: JsonField = JsonMissing.of() + private var stopSequences: JsonField>? = null + private var topK: JsonField = JsonMissing.of() + private var topP: JsonField = JsonMissing.of() + private var useCache: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(anthropicModelParams: AnthropicModelParams) = apply { + maxTokens = anthropicModelParams.maxTokens + temperature = anthropicModelParams.temperature + maxTokensToSample = anthropicModelParams.maxTokensToSample + stopSequences = anthropicModelParams.stopSequences.map { it.toMutableList() } + topK = anthropicModelParams.topK + topP = anthropicModelParams.topP + useCache = anthropicModelParams.useCache + additionalProperties = anthropicModelParams.additionalProperties.toMutableMap() + } + + fun maxTokens(maxTokens: Double) = maxTokens(JsonField.of(maxTokens)) + + /** + * Sets [Builder.maxTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.maxTokens] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun maxTokens(maxTokens: JsonField) = apply { this.maxTokens = maxTokens } + + fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) + + /** + * Sets [Builder.temperature] to an arbitrary JSON value. + * + * You should usually call [Builder.temperature] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun temperature(temperature: JsonField) = apply { + this.temperature = temperature + } + + /** This is a legacy parameter that should not be used. */ + fun maxTokensToSample(maxTokensToSample: Double) = + maxTokensToSample(JsonField.of(maxTokensToSample)) + + /** + * Sets [Builder.maxTokensToSample] to an arbitrary JSON value. + * + * You should usually call [Builder.maxTokensToSample] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun maxTokensToSample(maxTokensToSample: JsonField) = apply { + this.maxTokensToSample = maxTokensToSample + } + + fun stopSequences(stopSequences: List) = + stopSequences(JsonField.of(stopSequences)) + + /** + * Sets [Builder.stopSequences] to an arbitrary JSON value. + * + * You should usually call [Builder.stopSequences] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun stopSequences(stopSequences: JsonField>) = apply { + this.stopSequences = stopSequences.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [stopSequences]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addStopSequence(stopSequence: String) = apply { + stopSequences = + (stopSequences ?: JsonField.of(mutableListOf())).also { + checkKnown("stopSequences", it).add(stopSequence) + } + } + + fun topK(topK: Double) = topK(JsonField.of(topK)) + + /** + * Sets [Builder.topK] to an arbitrary JSON value. + * + * You should usually call [Builder.topK] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun topK(topK: JsonField) = apply { this.topK = topK } + + fun topP(topP: Double) = topP(JsonField.of(topP)) + + /** + * Sets [Builder.topP] to an arbitrary JSON value. + * + * You should usually call [Builder.topP] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun topP(topP: JsonField) = apply { this.topP = topP } + + fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) + + /** + * Sets [Builder.useCache] to an arbitrary JSON value. + * + * You should usually call [Builder.useCache] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun useCache(useCache: JsonField) = apply { this.useCache = useCache } + + 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 [AnthropicModelParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .maxTokens() + * .temperature() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): AnthropicModelParams = + AnthropicModelParams( + checkRequired("maxTokens", maxTokens), + checkRequired("temperature", temperature), + maxTokensToSample, + (stopSequences ?: JsonMissing.of()).map { it.toImmutable() }, + topK, + topP, + useCache, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): AnthropicModelParams = apply { + if (validated) { + return@apply + } + + maxTokens() + temperature() + maxTokensToSample() + stopSequences() + topK() + topP() + useCache() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (maxTokens.asKnown() == null) 0 else 1) + + (if (temperature.asKnown() == null) 0 else 1) + + (if (maxTokensToSample.asKnown() == null) 0 else 1) + + (stopSequences.asKnown()?.size ?: 0) + + (if (topK.asKnown() == null) 0 else 1) + + (if (topP.asKnown() == null) 0 else 1) + + (if (useCache.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AnthropicModelParams && + maxTokens == other.maxTokens && + temperature == other.temperature && + maxTokensToSample == other.maxTokensToSample && + stopSequences == other.stopSequences && + topK == other.topK && + topP == other.topP && + useCache == other.useCache && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + maxTokens, + temperature, + maxTokensToSample, + stopSequences, + topK, + topP, + useCache, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AnthropicModelParams{maxTokens=$maxTokens, temperature=$temperature, maxTokensToSample=$maxTokensToSample, stopSequences=$stopSequences, topK=$topK, topP=$topP, useCache=$useCache, additionalProperties=$additionalProperties}" + } + + class GoogleModelParams + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val maxOutputTokens: JsonField, + private val temperature: JsonField, + private val topK: JsonField, + private val topP: JsonField, + private val useCache: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("maxOutputTokens") + @ExcludeMissing + maxOutputTokens: JsonField = JsonMissing.of(), + @JsonProperty("temperature") + @ExcludeMissing + temperature: JsonField = JsonMissing.of(), + @JsonProperty("topK") @ExcludeMissing topK: JsonField = JsonMissing.of(), + @JsonProperty("topP") @ExcludeMissing topP: JsonField = JsonMissing.of(), + @JsonProperty("use_cache") + @ExcludeMissing + useCache: JsonField = JsonMissing.of(), + ) : this(maxOutputTokens, temperature, topK, topP, useCache, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun maxOutputTokens(): Double? = maxOutputTokens.getNullable("maxOutputTokens") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun temperature(): Double? = temperature.getNullable("temperature") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun topK(): Double? = topK.getNullable("topK") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun topP(): Double? = topP.getNullable("topP") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun useCache(): Boolean? = useCache.getNullable("use_cache") + + /** + * Returns the raw JSON value of [maxOutputTokens]. + * + * Unlike [maxOutputTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("maxOutputTokens") + @ExcludeMissing + fun _maxOutputTokens(): JsonField = maxOutputTokens + + /** + * Returns the raw JSON value of [temperature]. + * + * Unlike [temperature], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("temperature") + @ExcludeMissing + fun _temperature(): JsonField = temperature + + /** + * Returns the raw JSON value of [topK]. + * + * Unlike [topK], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("topK") @ExcludeMissing fun _topK(): JsonField = topK + + /** + * Returns the raw JSON value of [topP]. + * + * Unlike [topP], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("topP") @ExcludeMissing fun _topP(): JsonField = topP + + /** + * Returns the raw JSON value of [useCache]. + * + * Unlike [useCache], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("use_cache") + @ExcludeMissing + fun _useCache(): JsonField = useCache + + @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 [GoogleModelParams]. + */ + fun builder() = Builder() + } + + /** A builder for [GoogleModelParams]. */ + class Builder internal constructor() { + + private var maxOutputTokens: JsonField = JsonMissing.of() + private var temperature: JsonField = JsonMissing.of() + private var topK: JsonField = JsonMissing.of() + private var topP: JsonField = JsonMissing.of() + private var useCache: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(googleModelParams: GoogleModelParams) = apply { + maxOutputTokens = googleModelParams.maxOutputTokens + temperature = googleModelParams.temperature + topK = googleModelParams.topK + topP = googleModelParams.topP + useCache = googleModelParams.useCache + additionalProperties = googleModelParams.additionalProperties.toMutableMap() + } + + fun maxOutputTokens(maxOutputTokens: Double) = + maxOutputTokens(JsonField.of(maxOutputTokens)) + + /** + * Sets [Builder.maxOutputTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.maxOutputTokens] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun maxOutputTokens(maxOutputTokens: JsonField) = apply { + this.maxOutputTokens = maxOutputTokens + } + + fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) + + /** + * Sets [Builder.temperature] to an arbitrary JSON value. + * + * You should usually call [Builder.temperature] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun temperature(temperature: JsonField) = apply { + this.temperature = temperature + } + + fun topK(topK: Double) = topK(JsonField.of(topK)) + + /** + * Sets [Builder.topK] to an arbitrary JSON value. + * + * You should usually call [Builder.topK] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun topK(topK: JsonField) = apply { this.topK = topK } + + fun topP(topP: Double) = topP(JsonField.of(topP)) + + /** + * Sets [Builder.topP] to an arbitrary JSON value. + * + * You should usually call [Builder.topP] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun topP(topP: JsonField) = apply { this.topP = topP } + + fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) + + /** + * Sets [Builder.useCache] to an arbitrary JSON value. + * + * You should usually call [Builder.useCache] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun useCache(useCache: JsonField) = apply { this.useCache = useCache } + + 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 [GoogleModelParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GoogleModelParams = + GoogleModelParams( + maxOutputTokens, + temperature, + topK, + topP, + useCache, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GoogleModelParams = apply { + if (validated) { + return@apply + } + + maxOutputTokens() + temperature() + topK() + topP() + useCache() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (maxOutputTokens.asKnown() == null) 0 else 1) + + (if (temperature.asKnown() == null) 0 else 1) + + (if (topK.asKnown() == null) 0 else 1) + + (if (topP.asKnown() == null) 0 else 1) + + (if (useCache.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GoogleModelParams && + maxOutputTokens == other.maxOutputTokens && + temperature == other.temperature && + topK == other.topK && + topP == other.topP && + useCache == other.useCache && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + maxOutputTokens, + temperature, + topK, + topP, + useCache, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GoogleModelParams{maxOutputTokens=$maxOutputTokens, temperature=$temperature, topK=$topK, topP=$topP, useCache=$useCache, additionalProperties=$additionalProperties}" + } + + class WindowAiModelParams + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val temperature: JsonField, + private val topK: JsonField, + private val useCache: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("temperature") + @ExcludeMissing + temperature: JsonField = JsonMissing.of(), + @JsonProperty("topK") @ExcludeMissing topK: JsonField = JsonMissing.of(), + @JsonProperty("use_cache") + @ExcludeMissing + useCache: JsonField = JsonMissing.of(), + ) : this(temperature, topK, useCache, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun temperature(): Double? = temperature.getNullable("temperature") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun topK(): Double? = topK.getNullable("topK") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun useCache(): Boolean? = useCache.getNullable("use_cache") + + /** + * Returns the raw JSON value of [temperature]. + * + * Unlike [temperature], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("temperature") + @ExcludeMissing + fun _temperature(): JsonField = temperature + + /** + * Returns the raw JSON value of [topK]. + * + * Unlike [topK], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("topK") @ExcludeMissing fun _topK(): JsonField = topK + + /** + * Returns the raw JSON value of [useCache]. + * + * Unlike [useCache], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("use_cache") + @ExcludeMissing + fun _useCache(): JsonField = useCache + + @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 [WindowAiModelParams]. + */ + fun builder() = Builder() + } + + /** A builder for [WindowAiModelParams]. */ + class Builder internal constructor() { + + private var temperature: JsonField = JsonMissing.of() + private var topK: JsonField = JsonMissing.of() + private var useCache: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(windowAiModelParams: WindowAiModelParams) = apply { + temperature = windowAiModelParams.temperature + topK = windowAiModelParams.topK + useCache = windowAiModelParams.useCache + additionalProperties = windowAiModelParams.additionalProperties.toMutableMap() + } + + fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) + + /** + * Sets [Builder.temperature] to an arbitrary JSON value. + * + * You should usually call [Builder.temperature] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun temperature(temperature: JsonField) = apply { + this.temperature = temperature + } + + fun topK(topK: Double) = topK(JsonField.of(topK)) + + /** + * Sets [Builder.topK] to an arbitrary JSON value. + * + * You should usually call [Builder.topK] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun topK(topK: JsonField) = apply { this.topK = topK } + + fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) + + /** + * Sets [Builder.useCache] to an arbitrary JSON value. + * + * You should usually call [Builder.useCache] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun useCache(useCache: JsonField) = apply { this.useCache = useCache } + + 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 [WindowAiModelParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): WindowAiModelParams = + WindowAiModelParams( + temperature, + topK, + useCache, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): WindowAiModelParams = apply { + if (validated) { + return@apply + } + + temperature() + topK() + useCache() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (temperature.asKnown() == null) 0 else 1) + + (if (topK.asKnown() == null) 0 else 1) + + (if (useCache.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is WindowAiModelParams && + temperature == other.temperature && + topK == other.topK && + useCache == other.useCache && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(temperature, topK, useCache, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "WindowAiModelParams{temperature=$temperature, topK=$topK, useCache=$useCache, additionalProperties=$additionalProperties}" + } + + class JsCompletionParams + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val useCache: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("use_cache") + @ExcludeMissing + useCache: JsonField = JsonMissing.of() + ) : this(useCache, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun useCache(): Boolean? = useCache.getNullable("use_cache") + + /** + * Returns the raw JSON value of [useCache]. + * + * Unlike [useCache], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("use_cache") + @ExcludeMissing + fun _useCache(): JsonField = useCache + + @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 [JsCompletionParams]. + */ + fun builder() = Builder() + } + + /** A builder for [JsCompletionParams]. */ + class Builder internal constructor() { + + private var useCache: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(jsCompletionParams: JsCompletionParams) = apply { + useCache = jsCompletionParams.useCache + additionalProperties = jsCompletionParams.additionalProperties.toMutableMap() + } + + fun useCache(useCache: Boolean) = useCache(JsonField.of(useCache)) + + /** + * Sets [Builder.useCache] to an arbitrary JSON value. + * + * You should usually call [Builder.useCache] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun useCache(useCache: JsonField) = apply { this.useCache = useCache } + + 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 [JsCompletionParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): JsCompletionParams = + JsCompletionParams(useCache, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): JsCompletionParams = apply { + if (validated) { + return@apply + } + + useCache() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (if (useCache.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is JsCompletionParams && + useCache == other.useCache && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(useCache, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "JsCompletionParams{useCache=$useCache, additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PromptOptions && + model == other.model && + params == other.params && + position == other.position && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(model, params, position, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PromptOptions{model=$model, params=$params, position=$position, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptReplaceParams.kt index 46d7396a..28d28df7 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptReplaceParams.kt @@ -5,426 +5,865 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create or replace prompt. If there is an existing prompt in the project with the same slug as the + * one specified in the request, will replace the existing prompt with the provided fields + */ class PromptReplaceParams -constructor( - private val name: String, - private val projectId: String, - private val slug: String, - private val description: String?, - private val functionType: FunctionType?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun projectId(): String = projectId - - fun slug(): String = slug - - fun description(): String? = description - - fun functionType(): FunctionType? = functionType - - fun promptData(): PromptData? = promptData - - fun tags(): List? = tags - - internal fun getBody(): PromptReplaceBody { - return PromptReplaceBody( - name, - projectId, - slug, - description, - functionType, - promptData, - tags, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = body.slug() + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun functionType(): FunctionType? = body.functionType() + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = body.promptData() + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = body.tags() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _slug(): JsonField = body._slug() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _functionType(): JsonField = body._functionType() + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _promptData(): JsonField = body._promptData() + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tags(): JsonField> = body._tags() + + 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 [PromptReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = PromptReplaceBody.Builder::class) - @NoAutoDetect - class PromptReplaceBody - internal constructor( - private val name: String?, - private val projectId: String?, - private val slug: String?, - private val description: String?, - private val functionType: FunctionType?, - private val promptData: PromptData?, - private val tags: List?, - private val additionalProperties: Map, - ) { + /** A builder for [PromptReplaceParams]. */ + class Builder internal constructor() { - private var hashCode: Int = 0 + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + internal fun from(promptReplaceParams: PromptReplaceParams) = apply { + body = promptReplaceParams.body.toBuilder() + additionalHeaders = promptReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = promptReplaceParams.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: + * - [name] + * - [projectId] + * - [slug] + * - [description] + * - [functionType] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the prompt */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") fun projectId(): String? = projectId + 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) } /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(): String? = slug + fun slug(slug: String) = apply { body.slug(slug) } - /** Textual description of the prompt */ - @JsonProperty("description") fun description(): String? = description + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun slug(slug: JsonField) = apply { body.slug(slug) } - @JsonProperty("function_type") fun functionType(): FunctionType? = functionType + /** Textual description of the prompt */ + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + fun functionType(functionType: FunctionType?) = apply { body.functionType(functionType) } + + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + body.functionType(functionType) + } /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") fun promptData(): PromptData? = promptData + fun promptData(promptData: PromptData?) = apply { body.promptData(promptData) } + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { body.promptData(promptData) } /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(): List? = tags + fun tags(tags: List?) = apply { body.tags(tags) } + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { body.tags(tags) } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { body.addTag(tag) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is PromptReplaceBody && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionType == other.functionType && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - projectId, - slug, - description, - functionType, - promptData, - tags, - additionalProperties, - ) - } - return hashCode + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "PromptReplaceBody{name=$name, projectId=$projectId, slug=$slug, description=$description, functionType=$functionType, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionType: FunctionType? = null - private var promptData: PromptData? = null - private var tags: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(promptReplaceBody: PromptReplaceBody) = apply { - this.name = promptReplaceBody.name - this.projectId = promptReplaceBody.projectId - this.slug = promptReplaceBody.slug - this.description = promptReplaceBody.description - this.functionType = promptReplaceBody.functionType - this.promptData = promptReplaceBody.promptData - this.tags = promptReplaceBody.tags - additionalProperties(promptReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the prompt */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Unique identifier for the project that the prompt belongs under */ - @JsonProperty("project_id") - fun projectId(projectId: String) = apply { this.projectId = projectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(slug: String) = apply { this.slug = slug } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Textual description of the prompt */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - @JsonProperty("function_type") - fun functionType(functionType: FunctionType) = apply { - this.functionType = functionType - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(tags: List) = apply { this.tags = tags } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): PromptReplaceBody = - PromptReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, - description, - functionType, - promptData, - tags?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is PromptReplaceParams && - this.name == other.name && - this.projectId == other.projectId && - this.slug == other.slug && - this.description == other.description && - this.functionType == other.functionType && - this.promptData == other.promptData && - this.tags == other.tags && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [PromptReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PromptReplaceParams = + PromptReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - name, - projectId, - slug, - description, - functionType, - promptData, - tags, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "PromptReplaceParams{name=$name, projectId=$projectId, slug=$slug, description=$description, functionType=$functionType, promptData=$promptData, tags=$tags, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + override fun _headers(): Headers = additionalHeaders - fun toBuilder() = Builder().from(this) + override fun _queryParams(): QueryParams = additionalQueryParams - companion object { + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val projectId: JsonField, + private val slug: JsonField, + private val description: JsonField, + private val functionType: JsonField, + private val promptData: JsonField, + private val tags: JsonField>, + private val additionalProperties: MutableMap, + ) { - fun builder() = Builder() - } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("function_type") + @ExcludeMissing + functionType: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this(name, projectId, slug, description, functionType, promptData, tags, mutableMapOf()) + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the prompt belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException 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 slug(): String = slug.getRequired("slug") + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun functionType(): FunctionType? = functionType.getNullable("function_type") + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug + + /** + * 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 [functionType]. + * + * Unlike [functionType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("function_type") + @ExcludeMissing + fun _functionType(): JsonField = functionType + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") + @ExcludeMissing + fun _promptData(): JsonField = promptData + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @NoAutoDetect - class Builder { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var name: String? = null - private var projectId: String? = null - private var slug: String? = null - private var description: String? = null - private var functionType: FunctionType? = null - private var promptData: PromptData? = null - private var tags: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(promptReplaceParams: PromptReplaceParams) = apply { - this.name = promptReplaceParams.name - this.projectId = promptReplaceParams.projectId - this.slug = promptReplaceParams.slug - this.description = promptReplaceParams.description - this.functionType = promptReplaceParams.functionType - this.promptData = promptReplaceParams.promptData - this.tags(promptReplaceParams.tags ?: listOf()) - additionalQueryParams(promptReplaceParams.additionalQueryParams) - additionalHeaders(promptReplaceParams.additionalHeaders) - additionalBodyProperties(promptReplaceParams.additionalBodyProperties) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + */ + fun builder() = Builder() } - /** Name of the prompt */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Unique identifier for the project that the prompt belongs under */ - fun projectId(projectId: String) = apply { this.projectId = projectId } + private var name: JsonField? = null + private var projectId: JsonField? = null + private var slug: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var functionType: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - /** Unique identifier for the prompt */ - fun slug(slug: String) = apply { this.slug = slug } + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + slug = body.slug + description = body.description + functionType = body.functionType + promptData = body.promptData + tags = body.tags.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - /** Textual description of the prompt */ - fun description(description: String) = apply { this.description = description } + /** Name of the prompt */ + fun name(name: String) = name(JsonField.of(name)) - fun functionType(functionType: FunctionType) = apply { this.functionType = functionType } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + /** Unique identifier for the project that the prompt belongs under */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - /** A list of tags for the prompt */ - fun tags(tags: List) = apply { - this.tags.clear() - this.tags.addAll(tags) - } + /** + * 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 } - /** A list of tags for the prompt */ - fun addTag(tag: String) = apply { this.tags.add(tag) } + /** Unique identifier for the prompt */ + fun slug(slug: String) = slug(JsonField.of(slug)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun slug(slug: JsonField) = apply { this.slug = slug } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun functionType(functionType: FunctionType?) = + functionType(JsonField.ofNullable(functionType)) + + /** + * Sets [Builder.functionType] to an arbitrary JSON value. + * + * You should usually call [Builder.functionType] with a well-typed [FunctionType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun functionType(functionType: JsonField) = apply { + this.functionType = functionType + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { + this.promptData = promptData + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = + (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .slug() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("slug", slug), + description, + functionType, + promptData, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply } - fun build(): PromptReplaceParams = - PromptReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(projectId) { "`projectId` is required but was not set" }, - checkNotNull(slug) { "`slug` is required but was not set" }, - description, - functionType, - promptData, - if (tags.size == 0) null else tags.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + name() + projectId() + slug() + description() + functionType()?.validate() + promptData()?.validate() + tags() + validated = true + } - class FunctionType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (slug.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (functionType.asKnown()?.validity() ?: 0) + + (promptData.asKnown()?.validity() ?: 0) + + (tags.asKnown()?.size ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is FunctionType && this.value == other.value + return other is Body && + name == other.name && + projectId == other.projectId && + slug == other.slug && + description == other.description && + functionType == other.functionType && + promptData == other.promptData && + tags == other.tags && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash( + name, + projectId, + slug, + description, + functionType, + promptData, + tags, + additionalProperties, + ) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, projectId=$projectId, slug=$slug, description=$description, functionType=$functionType, promptData=$promptData, tags=$tags, additionalProperties=$additionalProperties}" + } + + class FunctionType @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 { - val LLM = FunctionType(JsonField.of("llm")) + val LLM = of("llm") - val SCORER = FunctionType(JsonField.of("scorer")) + val SCORER = of("scorer") - val TASK = FunctionType(JsonField.of("task")) + val TASK = of("task") - val TOOL = FunctionType(JsonField.of("tool")) + val TOOL = of("tool") fun of(value: String) = FunctionType(JsonField.of(value)) } + /** An enum containing [FunctionType]'s known values. */ enum class Known { LLM, SCORER, @@ -432,14 +871,33 @@ constructor( TOOL, } + /** + * An enum containing [FunctionType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [FunctionType] 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 { LLM, SCORER, TASK, TOOL, + /** + * An enum member indicating that [FunctionType] 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) { LLM -> Value.LLM @@ -449,6 +907,15 @@ constructor( 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { LLM -> Known.LLM @@ -458,6 +925,71 @@ constructor( else -> throw BraintrustInvalidDataException("Unknown FunctionType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): FunctionType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 FunctionType && 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 PromptReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "PromptReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptRetrieveParams.kt index b5fd935e..a2d6d32e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptRetrieveParams.kt @@ -2,125 +2,184 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a prompt object by its id */ class PromptRetrieveParams -constructor( - private val promptId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val promptId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun promptId(): String = promptId + /** Prompt id */ + fun promptId(): String? = promptId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> promptId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): PromptRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [PromptRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [PromptRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var promptId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(promptRetrieveParams: PromptRetrieveParams) = apply { + promptId = promptRetrieveParams.promptId + additionalHeaders = promptRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = promptRetrieveParams.additionalQueryParams.toBuilder() } - return other is PromptRetrieveParams && - this.promptId == other.promptId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Prompt id */ + fun promptId(promptId: String?) = apply { this.promptId = promptId } - override fun hashCode(): Int { - return Objects.hash( - promptId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "PromptRetrieveParams{promptId=$promptId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var promptId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(promptRetrieveParams: PromptRetrieveParams) = apply { - this.promptId = promptRetrieveParams.promptId - additionalQueryParams(promptRetrieveParams.additionalQueryParams) - additionalHeaders(promptRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Prompt id */ - fun promptId(promptId: String) = apply { this.promptId = promptId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [PromptRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): PromptRetrieveParams = - PromptRetrieveParams( - checkNotNull(promptId) { "`promptId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) + PromptRetrieveParams(promptId, additionalHeaders.build(), additionalQueryParams.build()) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> promptId ?: "" + 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 PromptRetrieveParams && + promptId == other.promptId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(promptId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "PromptRetrieveParams{promptId=$promptId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptUpdateParams.kt index f0e9a758..68052854 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/PromptUpdateParams.kt @@ -3,357 +3,697 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update a prompt object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class PromptUpdateParams -constructor( - private val promptId: String, - private val description: String?, - private val name: String?, - private val promptData: PromptData?, - private val slug: String?, - private val tags: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun promptId(): String = promptId - - fun description(): String? = description - - fun name(): String? = name - - fun promptData(): PromptData? = promptData - - fun slug(): String? = slug - - fun tags(): List? = tags - - internal fun getBody(): PromptUpdateBody { - return PromptUpdateBody( - description, - name, - promptData, - slug, - tags, - additionalBodyProperties, - ) - } +private constructor( + private val promptId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Prompt id */ + fun promptId(): String? = promptId + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun promptData(): PromptData? = body.promptData() + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun slug(): String? = body.slug() + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tags(): List? = body.tags() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _promptData(): JsonField = body._promptData() + + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _slug(): JsonField = body._slug() + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tags(): JsonField> = body._tags() + + 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 - internal fun getQueryParams(): Map> = additionalQueryParams + fun toBuilder() = Builder().from(this) - internal fun getHeaders(): Map> = additionalHeaders + companion object { - fun getPathParam(index: Int): String { - return when (index) { - 0 -> promptId - else -> "" - } + fun none(): PromptUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [PromptUpdateParams]. */ + fun builder() = Builder() } - @JsonDeserialize(builder = PromptUpdateBody.Builder::class) - @NoAutoDetect - class PromptUpdateBody - internal constructor( - private val description: String?, - private val name: String?, - private val promptData: PromptData?, - private val slug: String?, - private val tags: List?, - private val additionalProperties: Map, - ) { + /** A builder for [PromptUpdateParams]. */ + class Builder internal constructor() { + + private var promptId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var hashCode: Int = 0 + internal fun from(promptUpdateParams: PromptUpdateParams) = apply { + promptId = promptUpdateParams.promptId + body = promptUpdateParams.body.toBuilder() + additionalHeaders = promptUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = promptUpdateParams.additionalQueryParams.toBuilder() + } + + /** Prompt id */ + fun promptId(promptId: String?) = apply { this.promptId = promptId } + + /** + * 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: + * - [description] + * - [name] + * - [promptData] + * - [slug] + * - [tags] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Textual description of the prompt */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** Name of the prompt */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") fun promptData(): PromptData? = promptData + fun promptData(promptData: PromptData?) = apply { body.promptData(promptData) } + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { body.promptData(promptData) } /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(): String? = slug + fun slug(slug: String?) = apply { body.slug(slug) } + + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun slug(slug: JsonField) = apply { body.slug(slug) } /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(): List? = tags + fun tags(tags: List?) = apply { body.tags(tags) } + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tags(tags: JsonField>) = apply { body.tags(tags) } + + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { body.addTag(tag) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return other is PromptUpdateBody && - this.description == other.description && - this.name == other.name && - this.promptData == other.promptData && - this.slug == other.slug && - this.tags == other.tags && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - description, - name, - promptData, - slug, - tags, - additionalProperties, - ) - } - return hashCode + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "PromptUpdateBody{description=$description, name=$name, promptData=$promptData, slug=$slug, tags=$tags, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var description: String? = null - private var name: String? = null - private var promptData: PromptData? = null - private var slug: String? = null - private var tags: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(promptUpdateBody: PromptUpdateBody) = apply { - this.description = promptUpdateBody.description - this.name = promptUpdateBody.name - this.promptData = promptUpdateBody.promptData - this.slug = promptUpdateBody.slug - this.tags = promptUpdateBody.tags - additionalProperties(promptUpdateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Textual description of the prompt */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the prompt */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The prompt, model, and its parameters */ - @JsonProperty("prompt_data") - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Unique identifier for the prompt */ - @JsonProperty("slug") fun slug(slug: String) = apply { this.slug = slug } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** A list of tags for the prompt */ - @JsonProperty("tags") fun tags(tags: List) = apply { this.tags = tags } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): PromptUpdateBody = - PromptUpdateBody( - description, - name, - promptData, - slug, - tags?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is PromptUpdateParams && - this.promptId == other.promptId && - this.description == other.description && - this.name == other.name && - this.promptData == other.promptData && - this.slug == other.slug && - this.tags == other.tags && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [PromptUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PromptUpdateParams = + PromptUpdateParams( + promptId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - promptId, - description, - name, - promptData, - slug, - tags, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun _body(): Body = body - override fun toString() = - "PromptUpdateParams{promptId=$promptId, description=$description, name=$name, promptData=$promptData, slug=$slug, tags=$tags, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun _pathParam(index: Int): String = + when (index) { + 0 -> promptId ?: "" + else -> "" + } - fun toBuilder() = Builder().from(this) + override fun _headers(): Headers = additionalHeaders - companion object { + override fun _queryParams(): QueryParams = additionalQueryParams - fun builder() = Builder() - } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val name: JsonField, + private val promptData: JsonField, + private val slug: JsonField, + private val tags: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("prompt_data") + @ExcludeMissing + promptData: JsonField = JsonMissing.of(), + @JsonProperty("slug") @ExcludeMissing slug: JsonField = JsonMissing.of(), + @JsonProperty("tags") @ExcludeMissing tags: JsonField> = JsonMissing.of(), + ) : this(description, name, promptData, slug, tags, mutableMapOf()) + + /** + * Textual description of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Name of the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * The prompt, model, and its parameters + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun promptData(): PromptData? = promptData.getNullable("prompt_data") + + /** + * Unique identifier for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun slug(): String? = slug.getNullable("slug") + + /** + * A list of tags for the prompt + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun tags(): List? = tags.getNullable("tags") + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [promptData]. + * + * Unlike [promptData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("prompt_data") + @ExcludeMissing + fun _promptData(): JsonField = promptData + + /** + * Returns the raw JSON value of [slug]. + * + * Unlike [slug], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("slug") @ExcludeMissing fun _slug(): JsonField = slug + + /** + * Returns the raw JSON value of [tags]. + * + * Unlike [tags], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tags") @ExcludeMissing fun _tags(): JsonField> = tags + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - @NoAutoDetect - class Builder { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - private var promptId: String? = null - private var description: String? = null - private var name: String? = null - private var promptData: PromptData? = null - private var slug: String? = null - private var tags: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun toBuilder() = Builder().from(this) - internal fun from(promptUpdateParams: PromptUpdateParams) = apply { - this.promptId = promptUpdateParams.promptId - this.description = promptUpdateParams.description - this.name = promptUpdateParams.name - this.promptData = promptUpdateParams.promptData - this.slug = promptUpdateParams.slug - this.tags(promptUpdateParams.tags ?: listOf()) - additionalQueryParams(promptUpdateParams.additionalQueryParams) - additionalHeaders(promptUpdateParams.additionalHeaders) - additionalBodyProperties(promptUpdateParams.additionalBodyProperties) + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - /** Prompt id */ - fun promptId(promptId: String) = apply { this.promptId = promptId } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** Textual description of the prompt */ - fun description(description: String) = apply { this.description = description } + private var description: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var promptData: JsonField = JsonMissing.of() + private var slug: JsonField = JsonMissing.of() + private var tags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - /** Name of the prompt */ - fun name(name: String) = apply { this.name = name } + internal fun from(body: Body) = apply { + description = body.description + name = body.name + promptData = body.promptData + slug = body.slug + tags = body.tags.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - /** The prompt, model, and its parameters */ - fun promptData(promptData: PromptData) = apply { this.promptData = promptData } + /** Textual description of the prompt */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } - /** Unique identifier for the prompt */ - fun slug(slug: String) = apply { this.slug = slug } + /** Name of the prompt */ + fun name(name: String?) = name(JsonField.ofNullable(name)) - /** A list of tags for the prompt */ - fun tags(tags: List) = apply { - this.tags.clear() - this.tags.addAll(tags) - } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** A list of tags for the prompt */ - fun addTag(tag: String) = apply { this.tags.add(tag) } + /** The prompt, model, and its parameters */ + fun promptData(promptData: PromptData?) = promptData(JsonField.ofNullable(promptData)) + + /** + * Sets [Builder.promptData] to an arbitrary JSON value. + * + * You should usually call [Builder.promptData] with a well-typed [PromptData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promptData(promptData: JsonField) = apply { + this.promptData = promptData + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** Unique identifier for the prompt */ + fun slug(slug: String?) = slug(JsonField.ofNullable(slug)) - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Sets [Builder.slug] to an arbitrary JSON value. + * + * You should usually call [Builder.slug] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun slug(slug: JsonField) = apply { this.slug = slug } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** A list of tags for the prompt */ + fun tags(tags: List?) = tags(JsonField.ofNullable(tags)) + + /** + * Sets [Builder.tags] to an arbitrary JSON value. + * + * You should usually call [Builder.tags] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tags(tags: JsonField>) = apply { + this.tags = tags.map { it.toMutableList() } + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Adds a single [String] to [tags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: String) = apply { + tags = + (tags ?: JsonField.of(mutableListOf())).also { checkKnown("tags", it).add(tag) } + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(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) + } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body( + description, + name, + promptData, + slug, + (tags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + description() + name() + promptData()?.validate() + slug() + tags() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (description.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (promptData.asKnown()?.validity() ?: 0) + + (if (slug.asKnown() == null) 0 else 1) + + (tags.asKnown()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + description == other.description && + name == other.name && + promptData == other.promptData && + slug == other.slug && + tags == other.tags && + additionalProperties == other.additionalProperties } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private val hashCode: Int by lazy { + Objects.hash(description, name, promptData, slug, tags, additionalProperties) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun hashCode(): Int = hashCode - fun build(): PromptUpdateParams = - PromptUpdateParams( - checkNotNull(promptId) { "`promptId` is required but was not set" }, - description, - name, - promptData, - slug, - if (tags.size == 0) null else tags.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) + override fun toString() = + "Body{description=$description, name=$name, promptData=$promptData, slug=$slug, tags=$tags, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PromptUpdateParams && + promptId == other.promptId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(promptId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "PromptUpdateParams{promptId=$promptId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RepoInfo.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RepoInfo.kt index d8ff8d63..722c7e53 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RepoInfo.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RepoInfo.kt @@ -6,293 +6,480 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** Metadata about the state of the repo when the experiment was created */ -@JsonDeserialize(builder = RepoInfo.Builder::class) -@NoAutoDetect class RepoInfo +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val commit: JsonField, - private val branch: JsonField, - private val tag: JsonField, - private val dirty: JsonField, - private val authorName: JsonField, private val authorEmail: JsonField, + private val authorName: JsonField, + private val branch: JsonField, + private val commit: JsonField, private val commitMessage: JsonField, private val commitTime: JsonField, + private val dirty: JsonField, private val gitDiff: JsonField, - private val additionalProperties: Map, + private val tag: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("author_email") + @ExcludeMissing + authorEmail: JsonField = JsonMissing.of(), + @JsonProperty("author_name") + @ExcludeMissing + authorName: JsonField = JsonMissing.of(), + @JsonProperty("branch") @ExcludeMissing branch: JsonField = JsonMissing.of(), + @JsonProperty("commit") @ExcludeMissing commit: JsonField = JsonMissing.of(), + @JsonProperty("commit_message") + @ExcludeMissing + commitMessage: JsonField = JsonMissing.of(), + @JsonProperty("commit_time") + @ExcludeMissing + commitTime: JsonField = JsonMissing.of(), + @JsonProperty("dirty") @ExcludeMissing dirty: JsonField = JsonMissing.of(), + @JsonProperty("git_diff") @ExcludeMissing gitDiff: JsonField = JsonMissing.of(), + @JsonProperty("tag") @ExcludeMissing tag: JsonField = JsonMissing.of(), + ) : this( + authorEmail, + authorName, + branch, + commit, + commitMessage, + commitTime, + dirty, + gitDiff, + tag, + mutableMapOf(), + ) - private var hashCode: Int = 0 + /** + * Email of the author of the most recent commit + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun authorEmail(): String? = authorEmail.getNullable("author_email") - /** SHA of most recent commit */ - fun commit(): String? = commit.getNullable("commit") + /** + * Name of the author of the most recent commit + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun authorName(): String? = authorName.getNullable("author_name") - /** Name of the branch the most recent commit belongs to */ + /** + * Name of the branch the most recent commit belongs to + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun branch(): String? = branch.getNullable("branch") - /** Name of the tag on the most recent commit */ - fun tag(): String? = tag.getNullable("tag") - - /** Whether or not the repo had uncommitted changes when snapshotted */ - fun dirty(): Boolean? = dirty.getNullable("dirty") - - /** Name of the author of the most recent commit */ - fun authorName(): String? = authorName.getNullable("author_name") - - /** Email of the author of the most recent commit */ - fun authorEmail(): String? = authorEmail.getNullable("author_email") + /** + * SHA of most recent commit + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun commit(): String? = commit.getNullable("commit") - /** Most recent commit message */ + /** + * Most recent commit message + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun commitMessage(): String? = commitMessage.getNullable("commit_message") - /** Time of the most recent commit */ + /** + * Time of the most recent commit + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun commitTime(): String? = commitTime.getNullable("commit_time") + /** + * Whether or not the repo had uncommitted changes when snapshotted + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun dirty(): Boolean? = dirty.getNullable("dirty") + /** * If the repo was dirty when run, this includes the diff between the current state of the repo * and the most recent commit. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun gitDiff(): String? = gitDiff.getNullable("git_diff") - /** SHA of most recent commit */ - @JsonProperty("commit") @ExcludeMissing fun _commit() = commit - - /** Name of the branch the most recent commit belongs to */ - @JsonProperty("branch") @ExcludeMissing fun _branch() = branch - - /** Name of the tag on the most recent commit */ - @JsonProperty("tag") @ExcludeMissing fun _tag() = tag - - /** Whether or not the repo had uncommitted changes when snapshotted */ - @JsonProperty("dirty") @ExcludeMissing fun _dirty() = dirty - - /** Name of the author of the most recent commit */ - @JsonProperty("author_name") @ExcludeMissing fun _authorName() = authorName + /** + * Name of the tag on the most recent commit + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tag(): String? = tag.getNullable("tag") - /** Email of the author of the most recent commit */ - @JsonProperty("author_email") @ExcludeMissing fun _authorEmail() = authorEmail + /** + * Returns the raw JSON value of [authorEmail]. + * + * Unlike [authorEmail], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("author_email") + @ExcludeMissing + fun _authorEmail(): JsonField = authorEmail - /** Most recent commit message */ - @JsonProperty("commit_message") @ExcludeMissing fun _commitMessage() = commitMessage + /** + * Returns the raw JSON value of [authorName]. + * + * Unlike [authorName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("author_name") @ExcludeMissing fun _authorName(): JsonField = authorName - /** Time of the most recent commit */ - @JsonProperty("commit_time") @ExcludeMissing fun _commitTime() = commitTime + /** + * Returns the raw JSON value of [branch]. + * + * Unlike [branch], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("branch") @ExcludeMissing fun _branch(): JsonField = branch /** - * If the repo was dirty when run, this includes the diff between the current state of the repo - * and the most recent commit. + * Returns the raw JSON value of [commit]. + * + * Unlike [commit], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("git_diff") @ExcludeMissing fun _gitDiff() = gitDiff + @JsonProperty("commit") @ExcludeMissing fun _commit(): JsonField = commit - @JsonAnyGetter + /** + * Returns the raw JSON value of [commitMessage]. + * + * Unlike [commitMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("commit_message") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _commitMessage(): JsonField = commitMessage - fun validate(): RepoInfo = apply { - if (!validated) { - commit() - branch() - tag() - dirty() - authorName() - authorEmail() - commitMessage() - commitTime() - gitDiff() - validated = true - } - } + /** + * Returns the raw JSON value of [commitTime]. + * + * Unlike [commitTime], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("commit_time") @ExcludeMissing fun _commitTime(): JsonField = commitTime - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [dirty]. + * + * Unlike [dirty], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dirty") @ExcludeMissing fun _dirty(): JsonField = dirty - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [gitDiff]. + * + * Unlike [gitDiff], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("git_diff") @ExcludeMissing fun _gitDiff(): JsonField = gitDiff - return other is RepoInfo && - this.commit == other.commit && - this.branch == other.branch && - this.tag == other.tag && - this.dirty == other.dirty && - this.authorName == other.authorName && - this.authorEmail == other.authorEmail && - this.commitMessage == other.commitMessage && - this.commitTime == other.commitTime && - this.gitDiff == other.gitDiff && - this.additionalProperties == other.additionalProperties - } + /** + * Returns the raw JSON value of [tag]. + * + * Unlike [tag], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tag") @ExcludeMissing fun _tag(): JsonField = tag - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - commit, - branch, - tag, - dirty, - authorName, - authorEmail, - commitMessage, - commitTime, - gitDiff, - additionalProperties, - ) - } - return hashCode + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "RepoInfo{commit=$commit, branch=$branch, tag=$tag, dirty=$dirty, authorName=$authorName, authorEmail=$authorEmail, commitMessage=$commitMessage, commitTime=$commitTime, gitDiff=$gitDiff, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** Returns a mutable builder for constructing an instance of [RepoInfo]. */ fun builder() = Builder() } - class Builder { + /** A builder for [RepoInfo]. */ + class Builder internal constructor() { - private var commit: JsonField = JsonMissing.of() - private var branch: JsonField = JsonMissing.of() - private var tag: JsonField = JsonMissing.of() - private var dirty: JsonField = JsonMissing.of() - private var authorName: JsonField = JsonMissing.of() private var authorEmail: JsonField = JsonMissing.of() + private var authorName: JsonField = JsonMissing.of() + private var branch: JsonField = JsonMissing.of() + private var commit: JsonField = JsonMissing.of() private var commitMessage: JsonField = JsonMissing.of() private var commitTime: JsonField = JsonMissing.of() + private var dirty: JsonField = JsonMissing.of() private var gitDiff: JsonField = JsonMissing.of() + private var tag: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(repoInfo: RepoInfo) = apply { - this.commit = repoInfo.commit - this.branch = repoInfo.branch - this.tag = repoInfo.tag - this.dirty = repoInfo.dirty - this.authorName = repoInfo.authorName - this.authorEmail = repoInfo.authorEmail - this.commitMessage = repoInfo.commitMessage - this.commitTime = repoInfo.commitTime - this.gitDiff = repoInfo.gitDiff - additionalProperties(repoInfo.additionalProperties) + authorEmail = repoInfo.authorEmail + authorName = repoInfo.authorName + branch = repoInfo.branch + commit = repoInfo.commit + commitMessage = repoInfo.commitMessage + commitTime = repoInfo.commitTime + dirty = repoInfo.dirty + gitDiff = repoInfo.gitDiff + tag = repoInfo.tag + additionalProperties = repoInfo.additionalProperties.toMutableMap() } - /** SHA of most recent commit */ - fun commit(commit: String) = commit(JsonField.of(commit)) - - /** SHA of most recent commit */ - @JsonProperty("commit") - @ExcludeMissing - fun commit(commit: JsonField) = apply { this.commit = commit } - - /** Name of the branch the most recent commit belongs to */ - fun branch(branch: String) = branch(JsonField.of(branch)) - - /** Name of the branch the most recent commit belongs to */ - @JsonProperty("branch") - @ExcludeMissing - fun branch(branch: JsonField) = apply { this.branch = branch } - - /** Name of the tag on the most recent commit */ - fun tag(tag: String) = tag(JsonField.of(tag)) - - /** Name of the tag on the most recent commit */ - @JsonProperty("tag") - @ExcludeMissing - fun tag(tag: JsonField) = apply { this.tag = tag } - - /** Whether or not the repo had uncommitted changes when snapshotted */ - fun dirty(dirty: Boolean) = dirty(JsonField.of(dirty)) + /** Email of the author of the most recent commit */ + fun authorEmail(authorEmail: String?) = authorEmail(JsonField.ofNullable(authorEmail)) - /** Whether or not the repo had uncommitted changes when snapshotted */ - @JsonProperty("dirty") - @ExcludeMissing - fun dirty(dirty: JsonField) = apply { this.dirty = dirty } + /** + * Sets [Builder.authorEmail] to an arbitrary JSON value. + * + * You should usually call [Builder.authorEmail] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun authorEmail(authorEmail: JsonField) = apply { this.authorEmail = authorEmail } /** Name of the author of the most recent commit */ - fun authorName(authorName: String) = authorName(JsonField.of(authorName)) + fun authorName(authorName: String?) = authorName(JsonField.ofNullable(authorName)) - /** Name of the author of the most recent commit */ - @JsonProperty("author_name") - @ExcludeMissing + /** + * Sets [Builder.authorName] to an arbitrary JSON value. + * + * You should usually call [Builder.authorName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun authorName(authorName: JsonField) = apply { this.authorName = authorName } - /** Email of the author of the most recent commit */ - fun authorEmail(authorEmail: String) = authorEmail(JsonField.of(authorEmail)) + /** Name of the branch the most recent commit belongs to */ + fun branch(branch: String?) = branch(JsonField.ofNullable(branch)) - /** Email of the author of the most recent commit */ - @JsonProperty("author_email") - @ExcludeMissing - fun authorEmail(authorEmail: JsonField) = apply { this.authorEmail = authorEmail } + /** + * Sets [Builder.branch] to an arbitrary JSON value. + * + * You should usually call [Builder.branch] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun branch(branch: JsonField) = apply { this.branch = branch } - /** Most recent commit message */ - fun commitMessage(commitMessage: String) = commitMessage(JsonField.of(commitMessage)) + /** SHA of most recent commit */ + fun commit(commit: String?) = commit(JsonField.ofNullable(commit)) + + /** + * Sets [Builder.commit] to an arbitrary JSON value. + * + * You should usually call [Builder.commit] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun commit(commit: JsonField) = apply { this.commit = commit } /** Most recent commit message */ - @JsonProperty("commit_message") - @ExcludeMissing + fun commitMessage(commitMessage: String?) = + commitMessage(JsonField.ofNullable(commitMessage)) + + /** + * Sets [Builder.commitMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.commitMessage] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun commitMessage(commitMessage: JsonField) = apply { this.commitMessage = commitMessage } /** Time of the most recent commit */ - fun commitTime(commitTime: String) = commitTime(JsonField.of(commitTime)) + fun commitTime(commitTime: String?) = commitTime(JsonField.ofNullable(commitTime)) - /** Time of the most recent commit */ - @JsonProperty("commit_time") - @ExcludeMissing + /** + * Sets [Builder.commitTime] to an arbitrary JSON value. + * + * You should usually call [Builder.commitTime] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun commitTime(commitTime: JsonField) = apply { this.commitTime = commitTime } + /** Whether or not the repo had uncommitted changes when snapshotted */ + fun dirty(dirty: Boolean?) = dirty(JsonField.ofNullable(dirty)) + /** - * If the repo was dirty when run, this includes the diff between the current state of the - * repo and the most recent commit. + * Alias for [Builder.dirty]. + * + * This unboxed primitive overload exists for backwards compatibility. */ - fun gitDiff(gitDiff: String) = gitDiff(JsonField.of(gitDiff)) + fun dirty(dirty: Boolean) = dirty(dirty as Boolean?) + + /** + * Sets [Builder.dirty] to an arbitrary JSON value. + * + * You should usually call [Builder.dirty] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun dirty(dirty: JsonField) = apply { this.dirty = dirty } /** * If the repo was dirty when run, this includes the diff between the current state of the * repo and the most recent commit. */ - @JsonProperty("git_diff") - @ExcludeMissing + fun gitDiff(gitDiff: String?) = gitDiff(JsonField.ofNullable(gitDiff)) + + /** + * Sets [Builder.gitDiff] to an arbitrary JSON value. + * + * You should usually call [Builder.gitDiff] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun gitDiff(gitDiff: JsonField) = apply { this.gitDiff = gitDiff } + /** Name of the tag on the most recent commit */ + fun tag(tag: String?) = tag(JsonField.ofNullable(tag)) + + /** + * Sets [Builder.tag] to an arbitrary JSON value. + * + * You should usually call [Builder.tag] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun tag(tag: JsonField) = apply { this.tag = tag } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RepoInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): RepoInfo = RepoInfo( - commit, - branch, - tag, - dirty, - authorName, authorEmail, + authorName, + branch, + commit, commitMessage, commitTime, + dirty, gitDiff, - additionalProperties.toUnmodifiable(), + tag, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): RepoInfo = apply { + if (validated) { + return@apply + } + + authorEmail() + authorName() + branch() + commit() + commitMessage() + commitTime() + dirty() + gitDiff() + tag() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (authorEmail.asKnown() == null) 0 else 1) + + (if (authorName.asKnown() == null) 0 else 1) + + (if (branch.asKnown() == null) 0 else 1) + + (if (commit.asKnown() == null) 0 else 1) + + (if (commitMessage.asKnown() == null) 0 else 1) + + (if (commitTime.asKnown() == null) 0 else 1) + + (if (dirty.asKnown() == null) 0 else 1) + + (if (gitDiff.asKnown() == null) 0 else 1) + + (if (tag.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RepoInfo && + authorEmail == other.authorEmail && + authorName == other.authorName && + branch == other.branch && + commit == other.commit && + commitMessage == other.commitMessage && + commitTime == other.commitTime && + dirty == other.dirty && + gitDiff == other.gitDiff && + tag == other.tag && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + authorEmail, + authorName, + branch, + commit, + commitMessage, + commitTime, + dirty, + gitDiff, + tag, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RepoInfo{authorEmail=$authorEmail, authorName=$authorName, branch=$branch, commit=$commit, commitMessage=$commitMessage, commitTime=$commitTime, dirty=$dirty, gitDiff=$gitDiff, tag=$tag, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Role.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Role.kt index c5d82a5a..58e82e4c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Role.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Role.kt @@ -2,20 +2,20 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects /** @@ -23,55 +23,101 @@ import java.util.Objects * * Roles can consist of individual permissions, as well as a set of roles they inherit from */ -@JsonDeserialize(builder = Role.Builder::class) -@NoAutoDetect class Role +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val orgId: JsonField, - private val userId: JsonField, - private val created: JsonField, private val name: JsonField, - private val description: JsonField, + private val created: JsonField, private val deletedAt: JsonField, + private val description: JsonField, private val memberPermissions: JsonField>, private val memberRoles: JsonField>, - private val additionalProperties: Map, + private val orgId: JsonField, + private val userId: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("member_permissions") + @ExcludeMissing + memberPermissions: JsonField> = JsonMissing.of(), + @JsonProperty("member_roles") + @ExcludeMissing + memberRoles: JsonField> = JsonMissing.of(), + @JsonProperty("org_id") @ExcludeMissing orgId: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( + id, + name, + created, + deletedAt, + description, + memberPermissions, + memberRoles, + orgId, + userId, + mutableMapOf(), + ) - /** Unique identifier for the role */ + /** + * Unique identifier for the role + * + * @throws BraintrustInvalidDataException 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") /** - * Unique id for the organization that the role belongs under - * - * A null org_id indicates a system role, which may be assigned to anybody and inherited by any - * other role, but cannot be edited. + * Name of the role * - * It is forbidden to change the org after creating a role + * @throws BraintrustInvalidDataException 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 orgId(): String? = orgId.getNullable("org_id") - - /** Identifies the user who created the role */ - fun userId(): String? = userId.getNullable("user_id") + fun name(): String = name.getRequired("name") - /** Date of role creation */ + /** + * Date of role creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** Name of the role */ - fun name(): String = name.getRequired("name") + /** + * Date of role deletion, or null if the role is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - /** Textual description of the role */ + /** + * Textual description of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun description(): String? = description.getNullable("description") - /** Date of role deletion, or null if the role is still active */ - fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - - /** (permission, restrict_object_type) tuples which belong to this role */ + /** + * (permission, restrict_object_type) tuples which belong to this role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun memberPermissions(): List? = memberPermissions.getNullable("member_permissions") @@ -80,12 +126,12 @@ private constructor( * * An inheriting role has all the permissions contained in its member roles, as well as all of * their inherited permissions + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ fun memberRoles(): List? = memberRoles.getNullable("member_roles") - /** Unique identifier for the role */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - /** * Unique id for the organization that the role belongs under * @@ -93,213 +139,227 @@ private constructor( * other role, but cannot be edited. * * It is forbidden to change the org after creating a role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("org_id") @ExcludeMissing fun _orgId() = orgId - - /** Identifies the user who created the role */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + fun orgId(): String? = orgId.getNullable("org_id") - /** Date of role creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * Identifies the user who created the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") - /** Name of the role */ - @JsonProperty("name") @ExcludeMissing fun _name() = name + /** + * 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 - /** Textual description of the role */ - @JsonProperty("description") @ExcludeMissing fun _description() = description + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") @ExcludeMissing fun _deletedAt() = deletedAt + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created - /** (permission, restrict_object_type) tuples which belong to this role */ - @JsonProperty("member_permissions") @ExcludeMissing fun _memberPermissions() = memberPermissions + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt /** - * Ids of the roles this role inherits from + * Returns the raw JSON value of [description]. * - * An inheriting role has all the permissions contained in its member roles, as well as all of - * their inherited permissions + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("member_roles") @ExcludeMissing fun _memberRoles() = memberRoles + @JsonProperty("description") @ExcludeMissing fun _description(): JsonField = description - @JsonAnyGetter + /** + * Returns the raw JSON value of [memberPermissions]. + * + * Unlike [memberPermissions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("member_permissions") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _memberPermissions(): JsonField> = memberPermissions - fun validate(): Role = apply { - if (!validated) { - id() - orgId() - userId() - created() - name() - description() - deletedAt() - memberPermissions()?.forEach { it.validate() } - memberRoles() - validated = true - } - } + /** + * Returns the raw JSON value of [memberRoles]. + * + * Unlike [memberRoles], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_roles") + @ExcludeMissing + fun _memberRoles(): JsonField> = memberRoles - fun toBuilder() = Builder().from(this) + /** + * Returns the raw JSON value of [orgId]. + * + * Unlike [orgId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_id") @ExcludeMissing fun _orgId(): JsonField = orgId - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId - return other is Role && - this.id == other.id && - this.orgId == other.orgId && - this.userId == other.userId && - this.created == other.created && - this.name == other.name && - this.description == other.description && - this.deletedAt == other.deletedAt && - this.memberPermissions == other.memberPermissions && - this.memberRoles == other.memberRoles && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - orgId, - userId, - created, - name, - description, - deletedAt, - memberPermissions, - memberRoles, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "Role{id=$id, orgId=$orgId, userId=$userId, created=$created, name=$name, description=$description, deletedAt=$deletedAt, memberPermissions=$memberPermissions, memberRoles=$memberRoles, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [Role]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [Role]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var orgId: JsonField = JsonMissing.of() - private var userId: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null private var created: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() - private var description: JsonField = JsonMissing.of() private var deletedAt: JsonField = JsonMissing.of() - private var memberPermissions: JsonField> = JsonMissing.of() - private var memberRoles: JsonField> = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var memberPermissions: JsonField>? = null + private var memberRoles: JsonField>? = null + private var orgId: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(role: Role) = apply { - this.id = role.id - this.orgId = role.orgId - this.userId = role.userId - this.created = role.created - this.name = role.name - this.description = role.description - this.deletedAt = role.deletedAt - this.memberPermissions = role.memberPermissions - this.memberRoles = role.memberRoles - additionalProperties(role.additionalProperties) + id = role.id + name = role.name + created = role.created + deletedAt = role.deletedAt + description = role.description + memberPermissions = role.memberPermissions.map { it.toMutableList() } + memberRoles = role.memberRoles.map { it.toMutableList() } + orgId = role.orgId + userId = role.userId + additionalProperties = role.additionalProperties.toMutableMap() } /** Unique identifier for the role */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the role */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - /** - * Unique id for the organization that the role belongs under + * Sets [Builder.id] to an arbitrary JSON value. * - * A null org_id indicates a system role, which may be assigned to anybody and inherited by - * any other role, but cannot be edited. - * - * It is forbidden to change the org after creating a role + * 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 orgId(orgId: String) = orgId(JsonField.of(orgId)) + fun id(id: JsonField) = apply { this.id = id } + + /** Name of the role */ + fun name(name: String) = name(JsonField.of(name)) /** - * Unique id for the organization that the role belongs under - * - * A null org_id indicates a system role, which may be assigned to anybody and inherited by - * any other role, but cannot be edited. + * Sets [Builder.name] to an arbitrary JSON value. * - * It is forbidden to change the org after creating a role + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - @JsonProperty("org_id") - @ExcludeMissing - fun orgId(orgId: JsonField) = apply { this.orgId = orgId } - - /** Identifies the user who created the role */ - fun userId(userId: String) = userId(JsonField.of(userId)) - - /** Identifies the user who created the role */ - @JsonProperty("user_id") - @ExcludeMissing - fun userId(userId: JsonField) = apply { this.userId = userId } + fun name(name: JsonField) = apply { this.name = name } /** Date of role creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) - /** Date of role creation */ - @JsonProperty("created") - @ExcludeMissing + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } - /** Name of the role */ - fun name(name: String) = name(JsonField.of(name)) + /** Date of role deletion, or null if the role is still active */ + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) - /** Name of the role */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } /** Textual description of the role */ - fun description(description: String) = description(JsonField.of(description)) + fun description(description: String?) = description(JsonField.ofNullable(description)) - /** Textual description of the role */ - @JsonProperty("description") - @ExcludeMissing + /** + * 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 } - /** Date of role deletion, or null if the role is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = deletedAt(JsonField.of(deletedAt)) - - /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") - @ExcludeMissing - fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } - /** (permission, restrict_object_type) tuples which belong to this role */ - fun memberPermissions(memberPermissions: List) = - memberPermissions(JsonField.of(memberPermissions)) + fun memberPermissions(memberPermissions: List?) = + memberPermissions(JsonField.ofNullable(memberPermissions)) - /** (permission, restrict_object_type) tuples which belong to this role */ - @JsonProperty("member_permissions") - @ExcludeMissing + /** + * Sets [Builder.memberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.memberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ fun memberPermissions(memberPermissions: JsonField>) = apply { - this.memberPermissions = memberPermissions + this.memberPermissions = memberPermissions.map { it.toMutableList() } } /** - * Ids of the roles this role inherits from + * Adds a single [MemberPermission] to [memberPermissions]. * - * An inheriting role has all the permissions contained in its member roles, as well as all - * of their inherited permissions + * @throws IllegalStateException if the field was previously set to a non-list. */ - fun memberRoles(memberRoles: List) = memberRoles(JsonField.of(memberRoles)) + fun addMemberPermission(memberPermission: MemberPermission) = apply { + memberPermissions = + (memberPermissions ?: JsonField.of(mutableListOf())).also { + checkKnown("memberPermissions", it).add(memberPermission) + } + } /** * Ids of the roles this role inherits from @@ -307,132 +367,242 @@ private constructor( * An inheriting role has all the permissions contained in its member roles, as well as all * of their inherited permissions */ - @JsonProperty("member_roles") - @ExcludeMissing + fun memberRoles(memberRoles: List?) = memberRoles(JsonField.ofNullable(memberRoles)) + + /** + * Sets [Builder.memberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.memberRoles] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun memberRoles(memberRoles: JsonField>) = apply { - this.memberRoles = memberRoles + this.memberRoles = memberRoles.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [memberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberRole(memberRole: String) = apply { + memberRoles = + (memberRoles ?: JsonField.of(mutableListOf())).also { + checkKnown("memberRoles", it).add(memberRole) + } } + /** + * Unique id for the organization that the role belongs under + * + * A null org_id indicates a system role, which may be assigned to anybody and inherited by + * any other role, but cannot be edited. + * + * It is forbidden to change the org after creating a role + */ + fun orgId(orgId: String?) = orgId(JsonField.ofNullable(orgId)) + + /** + * Sets [Builder.orgId] to an arbitrary JSON value. + * + * You should usually call [Builder.orgId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgId(orgId: JsonField) = apply { this.orgId = orgId } + + /** Identifies the user who created the role */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [Role]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): Role = Role( - id, - orgId, - userId, + checkRequired("id", id), + checkRequired("name", name), created, - name, - description, deletedAt, - memberPermissions.map { it.toUnmodifiable() }, - memberRoles.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + description, + (memberPermissions ?: JsonMissing.of()).map { it.toImmutable() }, + (memberRoles ?: JsonMissing.of()).map { it.toImmutable() }, + orgId, + userId, + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = MemberPermission.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + id() + name() + created() + deletedAt() + description() + memberPermissions()?.forEach { it.validate() } + memberRoles() + orgId() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (memberPermissions.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (memberRoles.asKnown()?.size ?: 0) + + (if (orgId.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) + class MemberPermission + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val permission: JsonField, - private val restrictObjectType: JsonField, - private val additionalProperties: Map, + private val restrictObjectType: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + ) : this(permission, restrictObjectType, mutableMapOf()) /** * Each permission permits a certain type of operation on an object in the system * * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * + * @throws BraintrustInvalidDataException 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 permission(): Permission = permission.getRequired("permission") - /** The object type that the ACL applies to */ - fun restrictObjectType(): RestrictObjectType? = + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = restrictObjectType.getNullable("restrict_object_type") /** - * Each permission permits a certain type of operation on an object in the system + * Returns the raw JSON value of [permission]. * - * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("permission") @ExcludeMissing fun _permission() = permission + @JsonProperty("permission") + @ExcludeMissing + fun _permission(): JsonField = permission - /** The object type that the ACL applies to */ + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ @JsonProperty("restrict_object_type") @ExcludeMissing - fun _restrictObjectType() = restrictObjectType + fun _restrictObjectType(): JsonField = restrictObjectType + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): MemberPermission = apply { - if (!validated) { - permission() - restrictObjectType() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is MemberPermission && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - permission, - restrictObjectType, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "MemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [MemberPermission]. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [MemberPermission]. */ + class Builder internal constructor() { - private var permission: JsonField = JsonMissing.of() - private var restrictObjectType: JsonField = JsonMissing.of() + private var permission: JsonField? = null + private var restrictObjectType: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(memberPermission: MemberPermission) = apply { - this.permission = memberPermission.permission - this.restrictObjectType = memberPermission.restrictObjectType - additionalProperties(memberPermission.additionalProperties) + permission = memberPermission.permission + restrictObjectType = memberPermission.restrictObjectType + additionalProperties = memberPermission.additionalProperties.toMutableMap() } /** @@ -444,253 +614,156 @@ private constructor( fun permission(permission: Permission) = permission(JsonField.of(permission)) /** - * Each permission permits a certain type of operation on an object in the system + * Sets [Builder.permission] to an arbitrary JSON value. * - * Permissions can be assigned to to objects on an individual basis, or grouped into - * roles + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JsonProperty("permission") - @ExcludeMissing fun permission(permission: JsonField) = apply { this.permission = permission } /** The object type that the ACL applies to */ - fun restrictObjectType(restrictObjectType: RestrictObjectType) = - restrictObjectType(JsonField.of(restrictObjectType)) + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - @ExcludeMissing - fun restrictObjectType(restrictObjectType: JsonField) = apply { + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { this.restrictObjectType = restrictObjectType } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [MemberPermission]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): MemberPermission = MemberPermission( - permission, + checkRequired("permission", permission), restrictObjectType, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Permission && this.value == other.value + fun validate(): MemberPermission = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) + permission().validate() + restrictObjectType()?.validate() + validated = true + } - fun of(value: String) = Permission(JsonField.of(value)) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() + return other is MemberPermission && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + additionalProperties == other.additionalProperties } - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RestrictObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) - - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) + private val hashCode: Int by lazy { + Objects.hash(permission, restrictObjectType, additionalProperties) + } - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) + override fun hashCode(): Int = hashCode - fun of(value: String) = RestrictObjectType(JsonField.of(value)) - } + override fun toString() = + "MemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + return other is Role && + id == other.id && + name == other.name && + created == other.created && + deletedAt == other.deletedAt && + description == other.description && + memberPermissions == other.memberPermissions && + memberRoles == other.memberRoles && + orgId == other.orgId && + userId == other.userId && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + created, + deletedAt, + description, + memberPermissions, + memberRoles, + orgId, + userId, + additionalProperties, + ) + } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> - throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "Role{id=$id, name=$name, created=$created, deletedAt=$deletedAt, description=$description, memberPermissions=$memberPermissions, memberRoles=$memberRoles, orgId=$orgId, userId=$userId, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleCreateParams.kt index 09fbfa0b..0f54147d 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleCreateParams.kt @@ -2,81 +2,213 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create a new role. If there is an existing role with the same name as the one specified in the + * request, will return the existing role unmodified + */ class RoleCreateParams -constructor( - private val name: String, - private val description: String?, - private val memberPermissions: List?, - private val memberRoles: List?, - private val orgName: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun description(): String? = description - - fun memberPermissions(): List? = memberPermissions - - fun memberRoles(): List? = memberRoles - - fun orgName(): String? = orgName - - internal fun getBody(): RoleCreateBody { - return RoleCreateBody( - name, - description, - memberPermissions, - memberRoles, - orgName, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the role + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Textual description of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * (permission, restrict_object_type) tuples which belong to this role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberPermissions(): List? = body.memberPermissions() + + /** + * Ids of the roles this role inherits from + * + * An inheriting role has all the permissions contained in its member roles, as well as all of + * their inherited permissions + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberRoles(): List? = body.memberRoles() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * role belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [memberPermissions]. + * + * Unlike [memberPermissions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _memberPermissions(): JsonField> = body._memberPermissions() + + /** + * Returns the raw JSON value of [memberRoles]. + * + * Unlike [memberRoles], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _memberRoles(): JsonField> = body._memberRoles() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + 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 [RoleCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [RoleCreateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = RoleCreateBody.Builder::class) - @NoAutoDetect - class RoleCreateBody - internal constructor( - private val name: String?, - private val description: String?, - private val memberPermissions: List?, - private val memberRoles: List?, - private val orgName: String?, - private val additionalProperties: Map, - ) { + internal fun from(roleCreateParams: RoleCreateParams) = apply { + body = roleCreateParams.body.toBuilder() + additionalHeaders = roleCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = roleCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [description] + * - [memberPermissions] + * - [memberRoles] + * - [orgName] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the role */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Textual description of the role */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** (permission, restrict_object_type) tuples which belong to this role */ - @JsonProperty("member_permissions") - fun memberPermissions(): List? = memberPermissions + fun memberPermissions(memberPermissions: List?) = apply { + body.memberPermissions(memberPermissions) + } + + /** + * Sets [Builder.memberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.memberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun memberPermissions(memberPermissions: JsonField>) = apply { + body.memberPermissions(memberPermissions) + } + + /** + * Adds a single [MemberPermission] to [memberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberPermission(memberPermission: MemberPermission) = apply { + body.addMemberPermission(memberPermission) + } /** * Ids of the roles this role inherits from @@ -84,379 +216,640 @@ constructor( * An inheriting role has all the permissions contained in its member roles, as well as all * of their inherited permissions */ - @JsonProperty("member_roles") fun memberRoles(): List? = memberRoles + fun memberRoles(memberRoles: List?) = apply { body.memberRoles(memberRoles) } + + /** + * Sets [Builder.memberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.memberRoles] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberRoles(memberRoles: JsonField>) = apply { + body.memberRoles(memberRoles) + } + + /** + * Adds a single [String] to [memberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberRole(memberRole: String) = apply { body.addMemberRole(memberRole) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the role belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is RoleCreateBody && - this.name == other.name && - this.description == other.description && - this.memberPermissions == other.memberPermissions && - this.memberRoles == other.memberRoles && - this.orgName == other.orgName && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - description, - memberPermissions, - memberRoles, - orgName, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "RoleCreateBody{name=$name, description=$description, memberPermissions=$memberPermissions, memberRoles=$memberRoles, orgName=$orgName, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var description: String? = null - private var memberPermissions: List? = null - private var memberRoles: List? = null - private var orgName: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(roleCreateBody: RoleCreateBody) = apply { - this.name = roleCreateBody.name - this.description = roleCreateBody.description - this.memberPermissions = roleCreateBody.memberPermissions - this.memberRoles = roleCreateBody.memberRoles - this.orgName = roleCreateBody.orgName - additionalProperties(roleCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the role */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Textual description of the role */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** (permission, restrict_object_type) tuples which belong to this role */ - @JsonProperty("member_permissions") - fun memberPermissions(memberPermissions: List) = apply { - this.memberPermissions = memberPermissions - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * Ids of the roles this role inherits from - * - * An inheriting role has all the permissions contained in its member roles, as well as - * all of their inherited permissions - */ - @JsonProperty("member_roles") - fun memberRoles(memberRoles: List) = apply { this.memberRoles = memberRoles } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the role belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): RoleCreateBody = - RoleCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - description, - memberPermissions?.toUnmodifiable(), - memberRoles?.toUnmodifiable(), - orgName, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is RoleCreateParams && - this.name == other.name && - this.description == other.description && - this.memberPermissions == other.memberPermissions && - this.memberRoles == other.memberRoles && - this.orgName == other.orgName && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - name, - description, - memberPermissions, - memberRoles, - orgName, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "RoleCreateParams{name=$name, description=$description, memberPermissions=$memberPermissions, memberRoles=$memberRoles, orgName=$orgName, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [RoleCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RoleCreateParams = + RoleCreateParams(body.build(), additionalHeaders.build(), additionalQueryParams.build()) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var description: String? = null - private var memberPermissions: MutableList = mutableListOf() - private var memberRoles: MutableList = mutableListOf() - private var orgName: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(roleCreateParams: RoleCreateParams) = apply { - this.name = roleCreateParams.name - this.description = roleCreateParams.description - this.memberPermissions(roleCreateParams.memberPermissions ?: listOf()) - this.memberRoles(roleCreateParams.memberRoles ?: listOf()) - this.orgName = roleCreateParams.orgName - additionalQueryParams(roleCreateParams.additionalQueryParams) - additionalHeaders(roleCreateParams.additionalHeaders) - additionalBodyProperties(roleCreateParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the role */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val description: JsonField, + private val memberPermissions: JsonField>, + private val memberRoles: JsonField>, + private val orgName: JsonField, + private val additionalProperties: MutableMap, + ) { - /** Textual description of the role */ - fun description(description: String) = apply { this.description = description } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("member_permissions") + @ExcludeMissing + memberPermissions: JsonField> = JsonMissing.of(), + @JsonProperty("member_roles") + @ExcludeMissing + memberRoles: JsonField> = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + ) : this(name, description, memberPermissions, memberRoles, orgName, mutableMapOf()) - /** (permission, restrict_object_type) tuples which belong to this role */ - fun memberPermissions(memberPermissions: List) = apply { - this.memberPermissions.clear() - this.memberPermissions.addAll(memberPermissions) - } + /** + * Name of the role + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** (permission, restrict_object_type) tuples which belong to this role */ - fun addMemberPermission(memberPermission: MemberPermission) = apply { - this.memberPermissions.add(memberPermission) - } + /** + * Textual description of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") /** - * Ids of the roles this role inherits from + * (permission, restrict_object_type) tuples which belong to this role * - * An inheriting role has all the permissions contained in its member roles, as well as all - * of their inherited permissions + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun memberRoles(memberRoles: List) = apply { - this.memberRoles.clear() - this.memberRoles.addAll(memberRoles) - } + fun memberPermissions(): List? = + memberPermissions.getNullable("member_permissions") /** * Ids of the roles this role inherits from * * An inheriting role has all the permissions contained in its member roles, as well as all * of their inherited permissions + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun addMemberRole(memberRole: String) = apply { this.memberRoles.add(memberRole) } + fun memberRoles(): List? = memberRoles.getNullable("member_roles") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the role belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * 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 - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [memberPermissions]. + * + * Unlike [memberPermissions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("member_permissions") + @ExcludeMissing + fun _memberPermissions(): JsonField> = memberPermissions - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [memberRoles]. + * + * Unlike [memberRoles], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_roles") + @ExcludeMissing + fun _memberRoles(): JsonField> = memberRoles - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var name: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var memberPermissions: JsonField>? = null + private var memberRoles: JsonField>? = null + private var orgName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + name = body.name + description = body.description + memberPermissions = body.memberPermissions.map { it.toMutableList() } + memberRoles = body.memberRoles.map { it.toMutableList() } + orgName = body.orgName + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Name of the role */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Textual description of the role */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** (permission, restrict_object_type) tuples which belong to this role */ + fun memberPermissions(memberPermissions: List?) = + memberPermissions(JsonField.ofNullable(memberPermissions)) + + /** + * Sets [Builder.memberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.memberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun memberPermissions(memberPermissions: JsonField>) = apply { + this.memberPermissions = memberPermissions.map { it.toMutableList() } + } + + /** + * Adds a single [MemberPermission] to [memberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberPermission(memberPermission: MemberPermission) = apply { + memberPermissions = + (memberPermissions ?: JsonField.of(mutableListOf())).also { + checkKnown("memberPermissions", it).add(memberPermission) + } + } + + /** + * Ids of the roles this role inherits from + * + * An inheriting role has all the permissions contained in its member roles, as well as + * all of their inherited permissions + */ + fun memberRoles(memberRoles: List?) = + memberRoles(JsonField.ofNullable(memberRoles)) + + /** + * Sets [Builder.memberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.memberRoles] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberRoles(memberRoles: JsonField>) = apply { + this.memberRoles = memberRoles.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [memberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberRole(memberRole: String) = apply { + memberRoles = + (memberRoles ?: JsonField.of(mutableListOf())).also { + checkKnown("memberRoles", it).add(memberRole) + } + } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the role belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + description, + (memberPermissions ?: JsonMissing.of()).map { it.toImmutable() }, + (memberRoles ?: JsonMissing.of()).map { it.toImmutable() }, + orgName, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + description() + memberPermissions()?.forEach { it.validate() } + memberRoles() + orgName() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): RoleCreateParams = - RoleCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (memberPermissions.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (memberRoles.asKnown()?.size ?: 0) + + (if (orgName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + description == other.description && + memberPermissions == other.memberPermissions && + memberRoles == other.memberRoles && + orgName == other.orgName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + name, description, - if (memberPermissions.size == 0) null else memberPermissions.toUnmodifiable(), - if (memberRoles.size == 0) null else memberRoles.toUnmodifiable(), + memberPermissions, + memberRoles, orgName, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, description=$description, memberPermissions=$memberPermissions, memberRoles=$memberRoles, orgName=$orgName, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = MemberPermission.Builder::class) - @NoAutoDetect class MemberPermission + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val additionalProperties: Map, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + ) : this(permission, restrictObjectType, mutableMapOf()) /** * Each permission permits a certain type of operation on an object in the system * * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * + * @throws BraintrustInvalidDataException 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("permission") fun permission(): Permission? = permission + fun permission(): Permission = permission.getRequired("permission") - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") - @JsonAnyGetter + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) + fun _permission(): JsonField = permission - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - return other is MemberPermission && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - permission, - restrictObjectType, - additionalProperties, - ) - } - return hashCode + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "MemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [MemberPermission]. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [MemberPermission]. */ + class Builder internal constructor() { - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null + private var permission: JsonField? = null + private var restrictObjectType: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(memberPermission: MemberPermission) = apply { - this.permission = memberPermission.permission - this.restrictObjectType = memberPermission.restrictObjectType - additionalProperties(memberPermission.additionalProperties) + permission = memberPermission.permission + restrictObjectType = memberPermission.restrictObjectType + additionalProperties = memberPermission.additionalProperties.toMutableMap() } /** @@ -465,240 +858,137 @@ constructor( * Permissions can be assigned to to objects on an individual basis, or grouped into * roles */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun permission(permission: Permission) = permission(JsonField.of(permission)) + + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) + + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { this.restrictObjectType = restrictObjectType } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [MemberPermission]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): MemberPermission = MemberPermission( - checkNotNull(permission) { "`permission` is required but was not set" }, + checkRequired("permission", permission), restrictObjectType, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Permission && this.value == other.value + fun validate(): MemberPermission = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) - - fun of(value: String) = Permission(JsonField.of(value)) - } - - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + permission().validate() + restrictObjectType()?.validate() + validated = true + } - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) - return other is RestrictObjectType && this.value == other.value + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) + return other is MemberPermission && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + additionalProperties == other.additionalProperties + } - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) + private val hashCode: Int by lazy { + Objects.hash(permission, restrictObjectType, additionalProperties) + } - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) + override fun hashCode(): Int = hashCode - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) + override fun toString() = + "MemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + } - fun of(value: String) = RestrictObjectType(JsonField.of(value)) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + return other is RoleCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> - throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "RoleCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleDeleteParams.kt index c9b13625..94e948ec 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleDeleteParams.kt @@ -3,138 +3,166 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** Delete a role object by its id */ class RoleDeleteParams -constructor( - private val roleId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, +private constructor( + private val roleId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, -) { +) : Params { - fun roleId(): String = roleId + /** Role id */ + fun roleId(): String? = roleId - internal fun getBody(): Map? { - return additionalBodyProperties.ifEmpty { null } - } + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> roleId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): RoleDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [RoleDeleteParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [RoleDeleteParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var roleId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() - fun _additionalBodyProperties(): Map = additionalBodyProperties + internal fun from(roleDeleteParams: RoleDeleteParams) = apply { + roleId = roleDeleteParams.roleId + additionalHeaders = roleDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = roleDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = roleDeleteParams.additionalBodyProperties.toMutableMap() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + /** Role id */ + fun roleId(roleId: String?) = apply { this.roleId = roleId } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is RoleDeleteParams && - this.roleId == other.roleId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun hashCode(): Int { - return Objects.hash( - roleId, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - override fun toString() = - "RoleDeleteParams{roleId=$roleId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun toBuilder() = Builder().from(this) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - private var roleId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - internal fun from(roleDeleteParams: RoleDeleteParams) = apply { - this.roleId = roleDeleteParams.roleId - additionalQueryParams(roleDeleteParams.additionalQueryParams) - additionalHeaders(roleDeleteParams.additionalHeaders) - additionalBodyProperties(roleDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** Role id */ - fun roleId(roleId: String) = apply { this.roleId = roleId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - this.additionalBodyProperties.putAll(additionalBodyProperties) + putAllAdditionalBodyProperties(additionalBodyProperties) } fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + additionalBodyProperties.put(key, value) } fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = @@ -142,12 +170,55 @@ constructor( 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 [RoleDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): RoleDeleteParams = RoleDeleteParams( - checkNotNull(roleId) { "`roleId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + roleId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> roleId ?: "" + 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 RoleDeleteParams && + roleId == other.roleId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(roleId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "RoleDeleteParams{roleId=$roleId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPage.kt index 613c4afd..bf1f3609 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPage.kt @@ -2,172 +2,120 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.RoleService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see RoleService.list */ class RoleListPage private constructor( - private val rolesService: RoleService, + private val service: RoleService, private val params: RoleListParams, - private val response: Response, -) { + private val response: RoleListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [RoleListPageResponse], but gracefully handles missing data. + * + * @see RoleListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RoleListPage && - this.rolesService == other.rolesService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - rolesService, - params, - response, - ) - } - - override fun toString() = - "RoleListPage{rolesService=$rolesService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPageParams(): RoleListParams? { - if (!hasNextPage()) { - return null - } - - return if (params.endingBefore() != null) { - RoleListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): RoleListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - RoleListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): RoleListPage? { - return getNextPageParams()?.let { rolesService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(rolesService: RoleService, params: RoleListParams, response: Response) = - RoleListPage( - rolesService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): RoleListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): RoleListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): RoleListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [RoleListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [RoleListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: RoleService? = null + private var params: RoleListParams? = null + private var response: RoleListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(roleListPage: RoleListPage) = apply { + service = roleListPage.service + params = roleListPage.params + response = roleListPage.response } - override fun toString() = - "RoleListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: RoleService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: RoleListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: RoleListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [RoleListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RoleListPage = + RoleListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is RoleListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: RoleListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = "RoleListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPageAsync.kt index 42568a46..9caf064c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPageAsync.kt @@ -2,174 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.RoleServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see RoleServiceAsync.list */ class RoleListPageAsync private constructor( - private val rolesService: RoleServiceAsync, + private val service: RoleServiceAsync, private val params: RoleListParams, - private val response: Response, -) { + private val response: RoleListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [RoleListPageResponse], but gracefully handles missing data. + * + * @see RoleListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RoleListPageAsync && - this.rolesService == other.rolesService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - rolesService, - params, - response, - ) - } - - override fun toString() = - "RoleListPageAsync{rolesService=$rolesService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): RoleListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - RoleListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): RoleListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - RoleListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): RoleListPageAsync? { - return getNextPageParams()?.let { rolesService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(rolesService: RoleServiceAsync, params: RoleListParams, response: Response) = - RoleListPageAsync( - rolesService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): RoleListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): RoleListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): RoleListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [RoleListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [RoleListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: RoleServiceAsync? = null + private var params: RoleListParams? = null + private var response: RoleListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(roleListPageAsync: RoleListPageAsync) = apply { + service = roleListPageAsync.service + params = roleListPageAsync.params + response = roleListPageAsync.response } - override fun toString() = - "RoleListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: RoleServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: RoleListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: RoleListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [RoleListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RoleListPageAsync = + RoleListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is RoleListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: RoleListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "RoleListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPageResponse.kt new file mode 100644 index 00000000..2a0c6a6d --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListPageResponse.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 RoleListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of role objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [RoleListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [RoleListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(roleListPageResponse: RoleListPageResponse) = apply { + objects = roleListPageResponse.objects.map { it.toMutableList() } + additionalProperties = roleListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of role objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [Role] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: Role) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [RoleListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RoleListPageResponse = + RoleListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): RoleListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RoleListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RoleListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListParams.kt index cfc2b22e..2d013f63 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleListParams.kt @@ -2,106 +2,80 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all roles. The roles are sorted by creation date, with the most recently-created roles + * coming first + */ class RoleListParams -constructor( +private constructor( private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, private val orgName: String?, private val roleName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** Name of the role to search for */ fun roleName(): String? = roleName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.roleName?.let { params.put("role_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RoleListParams && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.roleName == other.roleName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - endingBefore, - ids, - limit, - orgName, - roleName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "RoleListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, roleName=$roleName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): RoleListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [RoleListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [RoleListParams]. */ + class Builder internal constructor() { private var endingBefore: String? = null private var ids: Ids? = null @@ -109,18 +83,18 @@ constructor( private var orgName: String? = null private var roleName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(roleListParams: RoleListParams) = apply { - this.endingBefore = roleListParams.endingBefore - this.ids = roleListParams.ids - this.limit = roleListParams.limit - this.orgName = roleListParams.orgName - this.roleName = roleListParams.roleName - this.startingAfter = roleListParams.startingAfter - additionalQueryParams(roleListParams.additionalQueryParams) - additionalHeaders(roleListParams.additionalHeaders) + endingBefore = roleListParams.endingBefore + ids = roleListParams.ids + limit = roleListParams.limit + orgName = roleListParams.orgName + roleName = roleListParams.roleName + startingAfter = roleListParams.startingAfter + additionalHeaders = roleListParams.additionalHeaders.toBuilder() + additionalQueryParams = roleListParams.additionalQueryParams.toBuilder() } /** @@ -130,34 +104,35 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** Name of the role to search for */ - fun roleName(roleName: String) = apply { this.roleName = roleName } + fun roleName(roleName: String?) = apply { this.roleName = roleName } /** * Pagination cursor id. @@ -166,48 +141,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [RoleListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): RoleListParams = RoleListParams( endingBefore, @@ -216,22 +254,46 @@ constructor( orgName, roleName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + roleName?.let { put("role_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -244,93 +306,74 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) + else -> throw IllegalStateException("Invalid Ids") } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true - } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is RoleListParams && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + roleName == other.roleName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + ids, + limit, + orgName, + roleName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "RoleListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, roleName=$roleName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleReplaceParams.kt index 426470d9..28143346 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleReplaceParams.kt @@ -2,81 +2,213 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Create or replace role. If there is an existing role with the same name as the one specified in + * the request, will replace the existing role with the provided fields + */ class RoleReplaceParams -constructor( - private val name: String, - private val description: String?, - private val memberPermissions: List?, - private val memberRoles: List?, - private val orgName: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun name(): String = name - - fun description(): String? = description - - fun memberPermissions(): List? = memberPermissions - - fun memberRoles(): List? = memberRoles - - fun orgName(): String? = orgName - - internal fun getBody(): RoleReplaceBody { - return RoleReplaceBody( - name, - description, - memberPermissions, - memberRoles, - orgName, - additionalBodyProperties, - ) +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the role + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Textual description of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * (permission, restrict_object_type) tuples which belong to this role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberPermissions(): List? = body.memberPermissions() + + /** + * Ids of the roles this role inherits from + * + * An inheriting role has all the permissions contained in its member roles, as well as all of + * their inherited permissions + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun memberRoles(): List? = body.memberRoles() + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that your + * API key belongs to multiple organizations, you may specify the name of the organization the + * role belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun orgName(): String? = body.orgName() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [memberPermissions]. + * + * Unlike [memberPermissions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _memberPermissions(): JsonField> = body._memberPermissions() + + /** + * Returns the raw JSON value of [memberRoles]. + * + * Unlike [memberRoles], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _memberRoles(): JsonField> = body._memberRoles() + + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _orgName(): JsonField = body._orgName() + + 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 [RoleReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [RoleReplaceParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - @JsonDeserialize(builder = RoleReplaceBody.Builder::class) - @NoAutoDetect - class RoleReplaceBody - internal constructor( - private val name: String?, - private val description: String?, - private val memberPermissions: List?, - private val memberRoles: List?, - private val orgName: String?, - private val additionalProperties: Map, - ) { + internal fun from(roleReplaceParams: RoleReplaceParams) = apply { + body = roleReplaceParams.body.toBuilder() + additionalHeaders = roleReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = roleReplaceParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [description] + * - [memberPermissions] + * - [memberRoles] + * - [orgName] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the role */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Textual description of the role */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** (permission, restrict_object_type) tuples which belong to this role */ - @JsonProperty("member_permissions") - fun memberPermissions(): List? = memberPermissions + fun memberPermissions(memberPermissions: List?) = apply { + body.memberPermissions(memberPermissions) + } + + /** + * Sets [Builder.memberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.memberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun memberPermissions(memberPermissions: JsonField>) = apply { + body.memberPermissions(memberPermissions) + } + + /** + * Adds a single [MemberPermission] to [memberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberPermission(memberPermission: MemberPermission) = apply { + body.addMemberPermission(memberPermission) + } /** * Ids of the roles this role inherits from @@ -84,379 +216,644 @@ constructor( * An inheriting role has all the permissions contained in its member roles, as well as all * of their inherited permissions */ - @JsonProperty("member_roles") fun memberRoles(): List? = memberRoles + fun memberRoles(memberRoles: List?) = apply { body.memberRoles(memberRoles) } + + /** + * Sets [Builder.memberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.memberRoles] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberRoles(memberRoles: JsonField>) = apply { + body.memberRoles(memberRoles) + } + + /** + * Adds a single [String] to [memberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberRole(memberRole: String) = apply { body.addMemberRole(memberRole) } /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the role belongs in. */ - @JsonProperty("org_name") fun orgName(): String? = orgName + fun orgName(orgName: String?) = apply { body.orgName(orgName) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun orgName(orgName: JsonField) = apply { body.orgName(orgName) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is RoleReplaceBody && - this.name == other.name && - this.description == other.description && - this.memberPermissions == other.memberPermissions && - this.memberRoles == other.memberRoles && - this.orgName == other.orgName && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - description, - memberPermissions, - memberRoles, - orgName, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "RoleReplaceBody{name=$name, description=$description, memberPermissions=$memberPermissions, memberRoles=$memberRoles, orgName=$orgName, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var description: String? = null - private var memberPermissions: List? = null - private var memberRoles: List? = null - private var orgName: String? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(roleReplaceBody: RoleReplaceBody) = apply { - this.name = roleReplaceBody.name - this.description = roleReplaceBody.description - this.memberPermissions = roleReplaceBody.memberPermissions - this.memberRoles = roleReplaceBody.memberRoles - this.orgName = roleReplaceBody.orgName - additionalProperties(roleReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the role */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Textual description of the role */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** (permission, restrict_object_type) tuples which belong to this role */ - @JsonProperty("member_permissions") - fun memberPermissions(memberPermissions: List) = apply { - this.memberPermissions = memberPermissions - } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * Ids of the roles this role inherits from - * - * An inheriting role has all the permissions contained in its member roles, as well as - * all of their inherited permissions - */ - @JsonProperty("member_roles") - fun memberRoles(memberRoles: List) = apply { this.memberRoles = memberRoles } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** - * For nearly all users, this parameter should be unnecessary. But in the rare case that - * your API key belongs to multiple organizations, you may specify the name of the - * organization the role belongs in. - */ - @JsonProperty("org_name") - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun build(): RoleReplaceBody = - RoleReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - description, - memberPermissions?.toUnmodifiable(), - memberRoles?.toUnmodifiable(), - orgName, - additionalProperties.toUnmodifiable(), - ) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - return other is RoleReplaceParams && - this.name == other.name && - this.description == other.description && - this.memberPermissions == other.memberPermissions && - this.memberRoles == other.memberRoles && - this.orgName == other.orgName && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - override fun hashCode(): Int { - return Objects.hash( - name, - description, - memberPermissions, - memberRoles, - orgName, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun toString() = - "RoleReplaceParams{name=$name, description=$description, memberPermissions=$memberPermissions, memberRoles=$memberRoles, orgName=$orgName, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun toBuilder() = Builder().from(this) + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - companion object { + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } - fun builder() = Builder() + /** + * Returns an immutable instance of [RoleReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RoleReplaceParams = + RoleReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @NoAutoDetect - class Builder { + fun _body(): Body = body - private var name: String? = null - private var description: String? = null - private var memberPermissions: MutableList = mutableListOf() - private var memberRoles: MutableList = mutableListOf() - private var orgName: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + override fun _headers(): Headers = additionalHeaders - internal fun from(roleReplaceParams: RoleReplaceParams) = apply { - this.name = roleReplaceParams.name - this.description = roleReplaceParams.description - this.memberPermissions(roleReplaceParams.memberPermissions ?: listOf()) - this.memberRoles(roleReplaceParams.memberRoles ?: listOf()) - this.orgName = roleReplaceParams.orgName - additionalQueryParams(roleReplaceParams.additionalQueryParams) - additionalHeaders(roleReplaceParams.additionalHeaders) - additionalBodyProperties(roleReplaceParams.additionalBodyProperties) - } + override fun _queryParams(): QueryParams = additionalQueryParams - /** Name of the role */ - fun name(name: String) = apply { this.name = name } + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val description: JsonField, + private val memberPermissions: JsonField>, + private val memberRoles: JsonField>, + private val orgName: JsonField, + private val additionalProperties: MutableMap, + ) { - /** Textual description of the role */ - fun description(description: String) = apply { this.description = description } + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("member_permissions") + @ExcludeMissing + memberPermissions: JsonField> = JsonMissing.of(), + @JsonProperty("member_roles") + @ExcludeMissing + memberRoles: JsonField> = JsonMissing.of(), + @JsonProperty("org_name") @ExcludeMissing orgName: JsonField = JsonMissing.of(), + ) : this(name, description, memberPermissions, memberRoles, orgName, mutableMapOf()) - /** (permission, restrict_object_type) tuples which belong to this role */ - fun memberPermissions(memberPermissions: List) = apply { - this.memberPermissions.clear() - this.memberPermissions.addAll(memberPermissions) - } + /** + * Name of the role + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** (permission, restrict_object_type) tuples which belong to this role */ - fun addMemberPermission(memberPermission: MemberPermission) = apply { - this.memberPermissions.add(memberPermission) - } + /** + * Textual description of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") /** - * Ids of the roles this role inherits from + * (permission, restrict_object_type) tuples which belong to this role * - * An inheriting role has all the permissions contained in its member roles, as well as all - * of their inherited permissions + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun memberRoles(memberRoles: List) = apply { - this.memberRoles.clear() - this.memberRoles.addAll(memberRoles) - } + fun memberPermissions(): List? = + memberPermissions.getNullable("member_permissions") /** * Ids of the roles this role inherits from * * An inheriting role has all the permissions contained in its member roles, as well as all * of their inherited permissions + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun addMemberRole(memberRole: String) = apply { this.memberRoles.add(memberRole) } + fun memberRoles(): List? = memberRoles.getNullable("member_roles") /** * For nearly all users, this parameter should be unnecessary. But in the rare case that * your API key belongs to multiple organizations, you may specify the name of the * organization the role belongs in. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(): String? = orgName.getNullable("org_name") - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * 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 - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Returns the raw JSON value of [memberPermissions]. + * + * Unlike [memberPermissions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("member_permissions") + @ExcludeMissing + fun _memberPermissions(): JsonField> = memberPermissions - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Returns the raw JSON value of [memberRoles]. + * + * Unlike [memberRoles], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("member_roles") + @ExcludeMissing + fun _memberRoles(): JsonField> = memberRoles - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** + * Returns the raw JSON value of [orgName]. + * + * Unlike [orgName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("org_name") @ExcludeMissing fun _orgName(): JsonField = orgName - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + fun toBuilder() = Builder().from(this) - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * ``` + */ + fun builder() = Builder() } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + /** A builder for [Body]. */ + class Builder internal constructor() { - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var name: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var memberPermissions: JsonField>? = null + private var memberRoles: JsonField>? = null + private var orgName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + name = body.name + description = body.description + memberPermissions = body.memberPermissions.map { it.toMutableList() } + memberRoles = body.memberRoles.map { it.toMutableList() } + orgName = body.orgName + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Name of the role */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Textual description of the role */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** (permission, restrict_object_type) tuples which belong to this role */ + fun memberPermissions(memberPermissions: List?) = + memberPermissions(JsonField.ofNullable(memberPermissions)) + + /** + * Sets [Builder.memberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.memberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun memberPermissions(memberPermissions: JsonField>) = apply { + this.memberPermissions = memberPermissions.map { it.toMutableList() } + } + + /** + * Adds a single [MemberPermission] to [memberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberPermission(memberPermission: MemberPermission) = apply { + memberPermissions = + (memberPermissions ?: JsonField.of(mutableListOf())).also { + checkKnown("memberPermissions", it).add(memberPermission) + } + } + + /** + * Ids of the roles this role inherits from + * + * An inheriting role has all the permissions contained in its member roles, as well as + * all of their inherited permissions + */ + fun memberRoles(memberRoles: List?) = + memberRoles(JsonField.ofNullable(memberRoles)) + + /** + * Sets [Builder.memberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.memberRoles] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun memberRoles(memberRoles: JsonField>) = apply { + this.memberRoles = memberRoles.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [memberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMemberRole(memberRole: String) = apply { + memberRoles = + (memberRoles ?: JsonField.of(mutableListOf())).also { + checkKnown("memberRoles", it).add(memberRole) + } + } + + /** + * For nearly all users, this parameter should be unnecessary. But in the rare case that + * your API key belongs to multiple organizations, you may specify the name of the + * organization the role belongs in. + */ + fun orgName(orgName: String?) = orgName(JsonField.ofNullable(orgName)) + + /** + * Sets [Builder.orgName] to an arbitrary JSON value. + * + * You should usually call [Builder.orgName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun orgName(orgName: JsonField) = apply { this.orgName = orgName } + + 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: + * ```kotlin + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + description, + (memberPermissions ?: JsonMissing.of()).map { it.toImmutable() }, + (memberRoles ?: JsonMissing.of()).map { it.toImmutable() }, + orgName, + additionalProperties.toMutableMap(), + ) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + description() + memberPermissions()?.forEach { it.validate() } + memberRoles() + orgName() + validated = true } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun build(): RoleReplaceParams = - RoleReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (memberPermissions.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (memberRoles.asKnown()?.size ?: 0) + + (if (orgName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + description == other.description && + memberPermissions == other.memberPermissions && + memberRoles == other.memberRoles && + orgName == other.orgName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + name, description, - if (memberPermissions.size == 0) null else memberPermissions.toUnmodifiable(), - if (memberRoles.size == 0) null else memberRoles.toUnmodifiable(), + memberPermissions, + memberRoles, orgName, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, description=$description, memberPermissions=$memberPermissions, memberRoles=$memberRoles, orgName=$orgName, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = MemberPermission.Builder::class) - @NoAutoDetect class MemberPermission + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val additionalProperties: Map, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + ) : this(permission, restrictObjectType, mutableMapOf()) /** * Each permission permits a certain type of operation on an object in the system * * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * + * @throws BraintrustInvalidDataException 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("permission") fun permission(): Permission? = permission + fun permission(): Permission = permission.getRequired("permission") - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") - @JsonAnyGetter + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) + fun _permission(): JsonField = permission - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - return other is MemberPermission && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - permission, - restrictObjectType, - additionalProperties, - ) - } - return hashCode + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun toString() = - "MemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [MemberPermission]. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [MemberPermission]. */ + class Builder internal constructor() { - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null + private var permission: JsonField? = null + private var restrictObjectType: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(memberPermission: MemberPermission) = apply { - this.permission = memberPermission.permission - this.restrictObjectType = memberPermission.restrictObjectType - additionalProperties(memberPermission.additionalProperties) + permission = memberPermission.permission + restrictObjectType = memberPermission.restrictObjectType + additionalProperties = memberPermission.additionalProperties.toMutableMap() } /** @@ -465,240 +862,137 @@ constructor( * Permissions can be assigned to to objects on an individual basis, or grouped into * roles */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun permission(permission: Permission) = permission(JsonField.of(permission)) + + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) + + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { this.restrictObjectType = restrictObjectType } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [MemberPermission]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): MemberPermission = MemberPermission( - checkNotNull(permission) { "`permission` is required but was not set" }, + checkRequired("permission", permission), restrictObjectType, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + private var validated: Boolean = false - return other is Permission && this.value == other.value + fun validate(): MemberPermission = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) - - fun of(value: String) = Permission(JsonField.of(value)) - } - - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + permission().validate() + restrictObjectType()?.validate() + validated = true + } - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) - return other is RestrictObjectType && this.value == other.value + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) + return other is MemberPermission && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + additionalProperties == other.additionalProperties + } - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) + private val hashCode: Int by lazy { + Objects.hash(permission, restrictObjectType, additionalProperties) + } - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) + override fun hashCode(): Int = hashCode - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) + override fun toString() = + "MemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + } - fun of(value: String) = RestrictObjectType(JsonField.of(value)) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + return other is RoleReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> - throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "RoleReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleRetrieveParams.kt index abf16d9d..1e445323 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleRetrieveParams.kt @@ -2,125 +2,184 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a role object by its id */ class RoleRetrieveParams -constructor( - private val roleId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val roleId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun roleId(): String = roleId + /** Role id */ + fun roleId(): String? = roleId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> roleId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): RoleRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [RoleRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [RoleRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var roleId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(roleRetrieveParams: RoleRetrieveParams) = apply { + roleId = roleRetrieveParams.roleId + additionalHeaders = roleRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = roleRetrieveParams.additionalQueryParams.toBuilder() } - return other is RoleRetrieveParams && - this.roleId == other.roleId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** Role id */ + fun roleId(roleId: String?) = apply { this.roleId = roleId } - override fun hashCode(): Int { - return Objects.hash( - roleId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "RoleRetrieveParams{roleId=$roleId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var roleId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(roleRetrieveParams: RoleRetrieveParams) = apply { - this.roleId = roleRetrieveParams.roleId - additionalQueryParams(roleRetrieveParams.additionalQueryParams) - additionalHeaders(roleRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** Role id */ - fun roleId(roleId: String) = apply { this.roleId = roleId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [RoleRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): RoleRetrieveParams = - RoleRetrieveParams( - checkNotNull(roleId) { "`roleId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) + RoleRetrieveParams(roleId, additionalHeaders.build(), additionalQueryParams.build()) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> roleId ?: "" + 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 RoleRetrieveParams && + roleId == other.roleId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(roleId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "RoleRetrieveParams{roleId=$roleId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleUpdateParams.kt index 5fee3b9d..ae4fd9ea 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/RoleUpdateParams.kt @@ -2,500 +2,974 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update a role object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class RoleUpdateParams -constructor( - private val roleId: String, - private val addMemberPermissions: List?, - private val addMemberRoles: List?, - private val description: String?, - private val name: String?, - private val removeMemberPermissions: List?, - private val removeMemberRoles: List?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val roleId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Role id */ + fun roleId(): String? = roleId + + /** + * A list of permissions to add to the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun addMemberPermissions(): List? = body.addMemberPermissions() + + /** + * A list of role IDs to add to the role's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun addMemberRoles(): List? = body.addMemberRoles() + + /** + * Textual description of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Name of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * A list of permissions to remove from the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun removeMemberPermissions(): List? = body.removeMemberPermissions() + + /** + * A list of role IDs to remove from the role's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun removeMemberRoles(): List? = body.removeMemberRoles() + + /** + * Returns the raw JSON value of [addMemberPermissions]. + * + * Unlike [addMemberPermissions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _addMemberPermissions(): JsonField> = body._addMemberPermissions() + + /** + * Returns the raw JSON value of [addMemberRoles]. + * + * Unlike [addMemberRoles], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _addMemberRoles(): JsonField> = body._addMemberRoles() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [removeMemberPermissions]. + * + * Unlike [removeMemberPermissions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + fun _removeMemberPermissions(): JsonField> = + body._removeMemberPermissions() + + /** + * Returns the raw JSON value of [removeMemberRoles]. + * + * Unlike [removeMemberRoles], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _removeMemberRoles(): JsonField> = body._removeMemberRoles() + + 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 roleId(): String = roleId - - fun addMemberPermissions(): List? = addMemberPermissions - - fun addMemberRoles(): List? = addMemberRoles - - fun description(): String? = description - - fun name(): String? = name + fun toBuilder() = Builder().from(this) - fun removeMemberPermissions(): List? = removeMemberPermissions + companion object { - fun removeMemberRoles(): List? = removeMemberRoles + fun none(): RoleUpdateParams = builder().build() - internal fun getBody(): RoleUpdateBody { - return RoleUpdateBody( - addMemberPermissions, - addMemberRoles, - description, - name, - removeMemberPermissions, - removeMemberRoles, - additionalBodyProperties, - ) + /** Returns a mutable builder for constructing an instance of [RoleUpdateParams]. */ + fun builder() = Builder() } - internal fun getQueryParams(): Map> = additionalQueryParams + /** A builder for [RoleUpdateParams]. */ + class Builder internal constructor() { - internal fun getHeaders(): Map> = additionalHeaders + private var roleId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun getPathParam(index: Int): String { - return when (index) { - 0 -> roleId - else -> "" + internal fun from(roleUpdateParams: RoleUpdateParams) = apply { + roleId = roleUpdateParams.roleId + body = roleUpdateParams.body.toBuilder() + additionalHeaders = roleUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = roleUpdateParams.additionalQueryParams.toBuilder() } - } - @JsonDeserialize(builder = RoleUpdateBody.Builder::class) - @NoAutoDetect - class RoleUpdateBody - internal constructor( - private val addMemberPermissions: List?, - private val addMemberRoles: List?, - private val description: String?, - private val name: String?, - private val removeMemberPermissions: List?, - private val removeMemberRoles: List?, - private val additionalProperties: Map, - ) { + /** Role id */ + fun roleId(roleId: String?) = apply { this.roleId = roleId } - private var hashCode: Int = 0 + /** + * 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: + * - [addMemberPermissions] + * - [addMemberRoles] + * - [description] + * - [name] + * - [removeMemberPermissions] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** A list of permissions to add to the role */ - @JsonProperty("add_member_permissions") - fun addMemberPermissions(): List? = addMemberPermissions + fun addMemberPermissions(addMemberPermissions: List?) = apply { + body.addMemberPermissions(addMemberPermissions) + } + + /** + * Sets [Builder.addMemberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun addMemberPermissions(addMemberPermissions: JsonField>) = + apply { + body.addMemberPermissions(addMemberPermissions) + } + + /** + * Adds a single [AddMemberPermission] to [addMemberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberPermission(addMemberPermission: AddMemberPermission) = apply { + body.addAddMemberPermission(addMemberPermission) + } /** A list of role IDs to add to the role's inheriting-from set */ - @JsonProperty("add_member_roles") fun addMemberRoles(): List? = addMemberRoles + fun addMemberRoles(addMemberRoles: List?) = apply { + body.addMemberRoles(addMemberRoles) + } + + /** + * Sets [Builder.addMemberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberRoles] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun addMemberRoles(addMemberRoles: JsonField>) = apply { + body.addMemberRoles(addMemberRoles) + } + + /** + * Adds a single [String] to [addMemberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberRole(addMemberRole: String) = apply { body.addAddMemberRole(addMemberRole) } /** Textual description of the role */ - @JsonProperty("description") fun description(): String? = description + fun description(description: String?) = apply { body.description(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 { body.description(description) } /** Name of the role */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** A list of permissions to remove from the role */ - @JsonProperty("remove_member_permissions") - fun removeMemberPermissions(): List? = removeMemberPermissions + fun removeMemberPermissions(removeMemberPermissions: List?) = + apply { + body.removeMemberPermissions(removeMemberPermissions) + } + + /** + * Sets [Builder.removeMemberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun removeMemberPermissions( + removeMemberPermissions: JsonField> + ) = apply { body.removeMemberPermissions(removeMemberPermissions) } + + /** + * Adds a single [RemoveMemberPermission] to [removeMemberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberPermission(removeMemberPermission: RemoveMemberPermission) = apply { + body.addRemoveMemberPermission(removeMemberPermission) + } /** A list of role IDs to remove from the role's inheriting-from set */ - @JsonProperty("remove_member_roles") - fun removeMemberRoles(): List? = removeMemberRoles + fun removeMemberRoles(removeMemberRoles: List?) = apply { + body.removeMemberRoles(removeMemberRoles) + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.removeMemberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberRoles] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun removeMemberRoles(removeMemberRoles: JsonField>) = apply { + body.removeMemberRoles(removeMemberRoles) + } - fun toBuilder() = Builder().from(this) + /** + * Adds a single [String] to [removeMemberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberRole(removeMemberRole: String) = apply { + body.addRemoveMemberRole(removeMemberRole) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - return other is RoleUpdateBody && - this.addMemberPermissions == other.addMemberPermissions && - this.addMemberRoles == other.addMemberRoles && - this.description == other.description && - this.name == other.name && - this.removeMemberPermissions == other.removeMemberPermissions && - this.removeMemberRoles == other.removeMemberRoles && - this.additionalProperties == other.additionalProperties + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - addMemberPermissions, - addMemberRoles, - description, - name, - removeMemberPermissions, - removeMemberRoles, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "RoleUpdateBody{addMemberPermissions=$addMemberPermissions, addMemberRoles=$addMemberRoles, description=$description, name=$name, removeMemberPermissions=$removeMemberPermissions, removeMemberRoles=$removeMemberRoles, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var addMemberPermissions: List? = null - private var addMemberRoles: List? = null - private var description: String? = null - private var name: String? = null - private var removeMemberPermissions: List? = null - private var removeMemberRoles: List? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(roleUpdateBody: RoleUpdateBody) = apply { - this.addMemberPermissions = roleUpdateBody.addMemberPermissions - this.addMemberRoles = roleUpdateBody.addMemberRoles - this.description = roleUpdateBody.description - this.name = roleUpdateBody.name - this.removeMemberPermissions = roleUpdateBody.removeMemberPermissions - this.removeMemberRoles = roleUpdateBody.removeMemberRoles - additionalProperties(roleUpdateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** A list of permissions to add to the role */ - @JsonProperty("add_member_permissions") - fun addMemberPermissions(addMemberPermissions: List) = apply { - this.addMemberPermissions = addMemberPermissions - } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** A list of role IDs to add to the role's inheriting-from set */ - @JsonProperty("add_member_roles") - fun addMemberRoles(addMemberRoles: List) = apply { - this.addMemberRoles = addMemberRoles - } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Textual description of the role */ - @JsonProperty("description") - fun description(description: String) = apply { this.description = description } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Name of the role */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** A list of permissions to remove from the role */ - @JsonProperty("remove_member_permissions") - fun removeMemberPermissions(removeMemberPermissions: List) = - apply { - this.removeMemberPermissions = removeMemberPermissions - } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** A list of role IDs to remove from the role's inheriting-from set */ - @JsonProperty("remove_member_roles") - fun removeMemberRoles(removeMemberRoles: List) = apply { - this.removeMemberRoles = removeMemberRoles - } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + 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 build(): RoleUpdateBody = - RoleUpdateBody( - addMemberPermissions?.toUnmodifiable(), - addMemberRoles?.toUnmodifiable(), - description, - name, - removeMemberPermissions?.toUnmodifiable(), - removeMemberRoles?.toUnmodifiable(), - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is RoleUpdateParams && - this.roleId == other.roleId && - this.addMemberPermissions == other.addMemberPermissions && - this.addMemberRoles == other.addMemberRoles && - this.description == other.description && - this.name == other.name && - this.removeMemberPermissions == other.removeMemberPermissions && - this.removeMemberRoles == other.removeMemberRoles && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [RoleUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): RoleUpdateParams = + RoleUpdateParams( + roleId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( - roleId, + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> roleId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val addMemberPermissions: JsonField>, + private val addMemberRoles: JsonField>, + private val description: JsonField, + private val name: JsonField, + private val removeMemberPermissions: JsonField>, + private val removeMemberRoles: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("add_member_permissions") + @ExcludeMissing + addMemberPermissions: JsonField> = JsonMissing.of(), + @JsonProperty("add_member_roles") + @ExcludeMissing + addMemberRoles: JsonField> = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("remove_member_permissions") + @ExcludeMissing + removeMemberPermissions: JsonField> = JsonMissing.of(), + @JsonProperty("remove_member_roles") + @ExcludeMissing + removeMemberRoles: JsonField> = JsonMissing.of(), + ) : this( addMemberPermissions, addMemberRoles, description, name, removeMemberPermissions, removeMemberRoles, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - override fun toString() = - "RoleUpdateParams{roleId=$roleId, addMemberPermissions=$addMemberPermissions, addMemberRoles=$addMemberRoles, description=$description, name=$name, removeMemberPermissions=$removeMemberPermissions, removeMemberRoles=$removeMemberRoles, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + /** + * A list of permissions to add to the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun addMemberPermissions(): List? = + addMemberPermissions.getNullable("add_member_permissions") - fun toBuilder() = Builder().from(this) + /** + * A list of role IDs to add to the role's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun addMemberRoles(): List? = addMemberRoles.getNullable("add_member_roles") - companion object { + /** + * Textual description of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") - fun builder() = Builder() - } + /** + * Name of the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") - @NoAutoDetect - class Builder { + /** + * A list of permissions to remove from the role + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun removeMemberPermissions(): List? = + removeMemberPermissions.getNullable("remove_member_permissions") - private var roleId: String? = null - private var addMemberPermissions: MutableList = mutableListOf() - private var addMemberRoles: MutableList = mutableListOf() - private var description: String? = null - private var name: String? = null - private var removeMemberPermissions: MutableList = mutableListOf() - private var removeMemberRoles: MutableList = mutableListOf() - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + /** + * A list of role IDs to remove from the role's inheriting-from set + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun removeMemberRoles(): List? = + removeMemberRoles.getNullable("remove_member_roles") - internal fun from(roleUpdateParams: RoleUpdateParams) = apply { - this.roleId = roleUpdateParams.roleId - this.addMemberPermissions(roleUpdateParams.addMemberPermissions ?: listOf()) - this.addMemberRoles(roleUpdateParams.addMemberRoles ?: listOf()) - this.description = roleUpdateParams.description - this.name = roleUpdateParams.name - this.removeMemberPermissions(roleUpdateParams.removeMemberPermissions ?: listOf()) - this.removeMemberRoles(roleUpdateParams.removeMemberRoles ?: listOf()) - additionalQueryParams(roleUpdateParams.additionalQueryParams) - additionalHeaders(roleUpdateParams.additionalHeaders) - additionalBodyProperties(roleUpdateParams.additionalBodyProperties) - } + /** + * Returns the raw JSON value of [addMemberPermissions]. + * + * Unlike [addMemberPermissions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("add_member_permissions") + @ExcludeMissing + fun _addMemberPermissions(): JsonField> = addMemberPermissions - /** Role id */ - fun roleId(roleId: String) = apply { this.roleId = roleId } + /** + * Returns the raw JSON value of [addMemberRoles]. + * + * Unlike [addMemberRoles], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("add_member_roles") + @ExcludeMissing + fun _addMemberRoles(): JsonField> = addMemberRoles - /** A list of permissions to add to the role */ - fun addMemberPermissions(addMemberPermissions: List) = apply { - this.addMemberPermissions.clear() - this.addMemberPermissions.addAll(addMemberPermissions) - } + /** + * 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 - /** A list of permissions to add to the role */ - fun addAddMemberPermission(addMemberPermission: AddMemberPermission) = apply { - this.addMemberPermissions.add(addMemberPermission) - } + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** A list of role IDs to add to the role's inheriting-from set */ - fun addMemberRoles(addMemberRoles: List) = apply { - this.addMemberRoles.clear() - this.addMemberRoles.addAll(addMemberRoles) - } + /** + * Returns the raw JSON value of [removeMemberPermissions]. + * + * Unlike [removeMemberPermissions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("remove_member_permissions") + @ExcludeMissing + fun _removeMemberPermissions(): JsonField> = + removeMemberPermissions - /** A list of role IDs to add to the role's inheriting-from set */ - fun addAddMemberRole(addMemberRole: String) = apply { - this.addMemberRoles.add(addMemberRole) + /** + * Returns the raw JSON value of [removeMemberRoles]. + * + * Unlike [removeMemberRoles], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("remove_member_roles") + @ExcludeMissing + fun _removeMemberRoles(): JsonField> = removeMemberRoles + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - /** Textual description of the role */ - fun description(description: String) = apply { this.description = description } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - /** Name of the role */ - fun name(name: String) = apply { this.name = name } + fun toBuilder() = Builder().from(this) - /** A list of permissions to remove from the role */ - fun removeMemberPermissions(removeMemberPermissions: List) = apply { - this.removeMemberPermissions.clear() - this.removeMemberPermissions.addAll(removeMemberPermissions) - } + companion object { - /** A list of permissions to remove from the role */ - fun addRemoveMemberPermission(removeMemberPermission: RemoveMemberPermission) = apply { - this.removeMemberPermissions.add(removeMemberPermission) + /** Returns a mutable builder for constructing an instance of [Body]. */ + fun builder() = Builder() } - /** A list of role IDs to remove from the role's inheriting-from set */ - fun removeMemberRoles(removeMemberRoles: List) = apply { - this.removeMemberRoles.clear() - this.removeMemberRoles.addAll(removeMemberRoles) - } + /** A builder for [Body]. */ + class Builder internal constructor() { - /** A list of role IDs to remove from the role's inheriting-from set */ - fun addRemoveMemberRole(removeMemberRole: String) = apply { - this.removeMemberRoles.add(removeMemberRole) - } + private var addMemberPermissions: JsonField>? = null + private var addMemberRoles: JsonField>? = null + private var description: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var removeMemberPermissions: JsonField>? = + null + private var removeMemberRoles: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + internal fun from(body: Body) = apply { + addMemberPermissions = body.addMemberPermissions.map { it.toMutableList() } + addMemberRoles = body.addMemberRoles.map { it.toMutableList() } + description = body.description + name = body.name + removeMemberPermissions = body.removeMemberPermissions.map { it.toMutableList() } + removeMemberRoles = body.removeMemberRoles.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** A list of permissions to add to the role */ + fun addMemberPermissions(addMemberPermissions: List?) = + addMemberPermissions(JsonField.ofNullable(addMemberPermissions)) - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Sets [Builder.addMemberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun addMemberPermissions(addMemberPermissions: JsonField>) = + apply { + this.addMemberPermissions = addMemberPermissions.map { it.toMutableList() } + } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Adds a single [AddMemberPermission] to [addMemberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberPermission(addMemberPermission: AddMemberPermission) = apply { + addMemberPermissions = + (addMemberPermissions ?: JsonField.of(mutableListOf())).also { + checkKnown("addMemberPermissions", it).add(addMemberPermission) + } + } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** A list of role IDs to add to the role's inheriting-from set */ + fun addMemberRoles(addMemberRoles: List?) = + addMemberRoles(JsonField.ofNullable(addMemberRoles)) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Sets [Builder.addMemberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.addMemberRoles] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun addMemberRoles(addMemberRoles: JsonField>) = apply { + this.addMemberRoles = addMemberRoles.map { it.toMutableList() } + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + /** + * Adds a single [String] to [addMemberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAddMemberRole(addMemberRole: String) = apply { + addMemberRoles = + (addMemberRoles ?: JsonField.of(mutableListOf())).also { + checkKnown("addMemberRoles", it).add(addMemberRole) + } + } + + /** Textual description of the role */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** Name of the role */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + /** A list of permissions to remove from the role */ + fun removeMemberPermissions(removeMemberPermissions: List?) = + removeMemberPermissions(JsonField.ofNullable(removeMemberPermissions)) + + /** + * Sets [Builder.removeMemberPermissions] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberPermissions] with a well-typed + * `List` value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun removeMemberPermissions( + removeMemberPermissions: JsonField> + ) = apply { + this.removeMemberPermissions = removeMemberPermissions.map { it.toMutableList() } + } + + /** + * Adds a single [RemoveMemberPermission] to [removeMemberPermissions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberPermission(removeMemberPermission: RemoveMemberPermission) = apply { + removeMemberPermissions = + (removeMemberPermissions ?: JsonField.of(mutableListOf())).also { + checkKnown("removeMemberPermissions", it).add(removeMemberPermission) + } + } + + /** A list of role IDs to remove from the role's inheriting-from set */ + fun removeMemberRoles(removeMemberRoles: List?) = + removeMemberRoles(JsonField.ofNullable(removeMemberRoles)) + + /** + * Sets [Builder.removeMemberRoles] to an arbitrary JSON value. + * + * You should usually call [Builder.removeMemberRoles] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun removeMemberRoles(removeMemberRoles: JsonField>) = apply { + this.removeMemberRoles = removeMemberRoles.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [removeMemberRoles]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRemoveMemberRole(removeMemberRole: String) = apply { + removeMemberRoles = + (removeMemberRoles ?: JsonField.of(mutableListOf())).also { + checkKnown("removeMemberRoles", it).add(removeMemberRole) + } + } + + 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( + (addMemberPermissions ?: JsonMissing.of()).map { it.toImmutable() }, + (addMemberRoles ?: JsonMissing.of()).map { it.toImmutable() }, + description, + name, + (removeMemberPermissions ?: JsonMissing.of()).map { it.toImmutable() }, + (removeMemberRoles ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + addMemberPermissions()?.forEach { it.validate() } + addMemberRoles() + description() + name() + removeMemberPermissions()?.forEach { it.validate() } + removeMemberRoles() + validated = true } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (addMemberPermissions.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (addMemberRoles.asKnown()?.size ?: 0) + + (if (description.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (removeMemberPermissions.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + (removeMemberRoles.asKnown()?.size ?: 0) - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + return other is Body && + addMemberPermissions == other.addMemberPermissions && + addMemberRoles == other.addMemberRoles && + description == other.description && + name == other.name && + removeMemberPermissions == other.removeMemberPermissions && + removeMemberRoles == other.removeMemberRoles && + additionalProperties == other.additionalProperties } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - - fun build(): RoleUpdateParams = - RoleUpdateParams( - checkNotNull(roleId) { "`roleId` is required but was not set" }, - if (addMemberPermissions.size == 0) null else addMemberPermissions.toUnmodifiable(), - if (addMemberRoles.size == 0) null else addMemberRoles.toUnmodifiable(), + private val hashCode: Int by lazy { + Objects.hash( + addMemberPermissions, + addMemberRoles, description, name, - if (removeMemberPermissions.size == 0) null - else removeMemberPermissions.toUnmodifiable(), - if (removeMemberRoles.size == 0) null else removeMemberRoles.toUnmodifiable(), - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + removeMemberPermissions, + removeMemberRoles, + additionalProperties, ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{addMemberPermissions=$addMemberPermissions, addMemberRoles=$addMemberRoles, description=$description, name=$name, removeMemberPermissions=$removeMemberPermissions, removeMemberRoles=$removeMemberRoles, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = AddMemberPermission.Builder::class) - @NoAutoDetect class AddMemberPermission + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val additionalProperties: Map, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + ) : this(permission, restrictObjectType, mutableMapOf()) /** * Each permission permits a certain type of operation on an object in the system * * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * + * @throws BraintrustInvalidDataException 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("permission") fun permission(): Permission? = permission + fun permission(): Permission = permission.getRequired("permission") - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") - @JsonAnyGetter + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) + fun _permission(): JsonField = permission - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - return other is AddMemberPermission && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - permission, - restrictObjectType, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "AddMemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [AddMemberPermission]. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [AddMemberPermission]. */ + class Builder internal constructor() { - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null + private var permission: JsonField? = null + private var restrictObjectType: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(addMemberPermission: AddMemberPermission) = apply { - this.permission = addMemberPermission.permission - this.restrictObjectType = addMemberPermission.restrictObjectType - additionalProperties(addMemberPermission.additionalProperties) + permission = addMemberPermission.permission + restrictObjectType = addMemberPermission.restrictObjectType + additionalProperties = addMemberPermission.additionalProperties.toMutableMap() } /** @@ -504,312 +978,216 @@ constructor( * Permissions can be assigned to to objects on an individual basis, or grouped into * roles */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun permission(permission: Permission) = permission(JsonField.of(permission)) + + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) + + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { this.restrictObjectType = restrictObjectType } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [AddMemberPermission]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): AddMemberPermission = AddMemberPermission( - checkNotNull(permission) { "`permission` is required but was not set" }, + checkRequired("permission", permission), restrictObjectType, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Permission && this.value == other.value - } - - override fun hashCode() = value.hashCode() + private var validated: Boolean = false - override fun toString() = value.toString() - - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) - - fun of(value: String) = Permission(JsonField.of(value)) - } - - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, + fun validate(): AddMemberPermission = apply { + if (validated) { + return@apply } - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() + permission().validate() + restrictObjectType()?.validate() + validated = true } - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RestrictObjectType && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) - - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) - - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) - - fun of(value: String) = RestrictObjectType(JsonField.of(value)) - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + return other is AddMemberPermission && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { + Objects.hash(permission, restrictObjectType, additionalProperties) + } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> - throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "AddMemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" } - @JsonDeserialize(builder = RemoveMemberPermission.Builder::class) - @NoAutoDetect class RemoveMemberPermission + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val permission: Permission?, - private val restrictObjectType: RestrictObjectType?, - private val additionalProperties: Map, + private val permission: JsonField, + private val restrictObjectType: JsonField, + private val additionalProperties: MutableMap, ) { - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("permission") + @ExcludeMissing + permission: JsonField = JsonMissing.of(), + @JsonProperty("restrict_object_type") + @ExcludeMissing + restrictObjectType: JsonField = JsonMissing.of(), + ) : this(permission, restrictObjectType, mutableMapOf()) /** * Each permission permits a certain type of operation on an object in the system * * Permissions can be assigned to to objects on an individual basis, or grouped into roles + * + * @throws BraintrustInvalidDataException 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("permission") fun permission(): Permission? = permission + fun permission(): Permission = permission.getRequired("permission") - /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(): RestrictObjectType? = restrictObjectType + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun restrictObjectType(): AclObjectType? = + restrictObjectType.getNullable("restrict_object_type") - @JsonAnyGetter + /** + * Returns the raw JSON value of [permission]. + * + * Unlike [permission], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("permission") @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) + fun _permission(): JsonField = permission - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Returns the raw JSON value of [restrictObjectType]. + * + * Unlike [restrictObjectType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("restrict_object_type") + @ExcludeMissing + fun _restrictObjectType(): JsonField = restrictObjectType - return other is RemoveMemberPermission && - this.permission == other.permission && - this.restrictObjectType == other.restrictObjectType && - this.additionalProperties == other.additionalProperties + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - permission, - restrictObjectType, - additionalProperties, - ) - } - return hashCode - } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = - "RemoveMemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) companion object { + /** + * Returns a mutable builder for constructing an instance of [RemoveMemberPermission]. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [RemoveMemberPermission]. */ + class Builder internal constructor() { - private var permission: Permission? = null - private var restrictObjectType: RestrictObjectType? = null + private var permission: JsonField? = null + private var restrictObjectType: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(removeMemberPermission: RemoveMemberPermission) = apply { - this.permission = removeMemberPermission.permission - this.restrictObjectType = removeMemberPermission.restrictObjectType - additionalProperties(removeMemberPermission.additionalProperties) + permission = removeMemberPermission.permission + restrictObjectType = removeMemberPermission.restrictObjectType + additionalProperties = removeMemberPermission.additionalProperties.toMutableMap() } /** @@ -818,240 +1196,139 @@ constructor( * Permissions can be assigned to to objects on an individual basis, or grouped into * roles */ - @JsonProperty("permission") - fun permission(permission: Permission) = apply { this.permission = permission } + fun permission(permission: Permission) = permission(JsonField.of(permission)) + + /** + * Sets [Builder.permission] to an arbitrary JSON value. + * + * You should usually call [Builder.permission] with a well-typed [Permission] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun permission(permission: JsonField) = apply { + this.permission = permission + } /** The object type that the ACL applies to */ - @JsonProperty("restrict_object_type") - fun restrictObjectType(restrictObjectType: RestrictObjectType) = apply { + fun restrictObjectType(restrictObjectType: AclObjectType?) = + restrictObjectType(JsonField.ofNullable(restrictObjectType)) + + /** + * Sets [Builder.restrictObjectType] to an arbitrary JSON value. + * + * You should usually call [Builder.restrictObjectType] with a well-typed + * [AclObjectType] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun restrictObjectType(restrictObjectType: JsonField) = apply { this.restrictObjectType = restrictObjectType } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [RemoveMemberPermission]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .permission() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): RemoveMemberPermission = RemoveMemberPermission( - checkNotNull(permission) { "`permission` is required but was not set" }, + checkRequired("permission", permission), restrictObjectType, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } - class Permission - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + private var validated: Boolean = false - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Permission && this.value == other.value + fun validate(): RemoveMemberPermission = apply { + if (validated) { + return@apply } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val CREATE = Permission(JsonField.of("create")) - - val READ = Permission(JsonField.of("read")) - - val UPDATE = Permission(JsonField.of("update")) - - val DELETE = Permission(JsonField.of("delete")) - - val CREATE_ACLS = Permission(JsonField.of("create_acls")) - - val READ_ACLS = Permission(JsonField.of("read_acls")) - - val UPDATE_ACLS = Permission(JsonField.of("update_acls")) - - val DELETE_ACLS = Permission(JsonField.of("delete_acls")) + permission().validate() + restrictObjectType()?.validate() + validated = true + } - fun of(value: String) = Permission(JsonField.of(value)) + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - enum class Known { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (permission.asKnown()?.validity() ?: 0) + + (restrictObjectType.asKnown()?.validity() ?: 0) - enum class Value { - CREATE, - READ, - UPDATE, - DELETE, - CREATE_ACLS, - READ_ACLS, - UPDATE_ACLS, - DELETE_ACLS, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - CREATE -> Value.CREATE - READ -> Value.READ - UPDATE -> Value.UPDATE - DELETE -> Value.DELETE - CREATE_ACLS -> Value.CREATE_ACLS - READ_ACLS -> Value.READ_ACLS - UPDATE_ACLS -> Value.UPDATE_ACLS - DELETE_ACLS -> Value.DELETE_ACLS - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - CREATE -> Known.CREATE - READ -> Known.READ - UPDATE -> Known.UPDATE - DELETE -> Known.DELETE - CREATE_ACLS -> Known.CREATE_ACLS - READ_ACLS -> Known.READ_ACLS - UPDATE_ACLS -> Known.UPDATE_ACLS - DELETE_ACLS -> Known.DELETE_ACLS - else -> throw BraintrustInvalidDataException("Unknown Permission: $value") - } - - fun asString(): String = _value().asStringOrThrow() + return other is RemoveMemberPermission && + permission == other.permission && + restrictObjectType == other.restrictObjectType && + additionalProperties == other.additionalProperties } - class RestrictObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is RestrictObjectType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = RestrictObjectType(JsonField.of("organization")) - - val PROJECT = RestrictObjectType(JsonField.of("project")) - - val EXPERIMENT = RestrictObjectType(JsonField.of("experiment")) - - val DATASET = RestrictObjectType(JsonField.of("dataset")) - - val PROMPT = RestrictObjectType(JsonField.of("prompt")) - - val PROMPT_SESSION = RestrictObjectType(JsonField.of("prompt_session")) - - val GROUP = RestrictObjectType(JsonField.of("group")) - - val ROLE = RestrictObjectType(JsonField.of("role")) - - val ORG_MEMBER = RestrictObjectType(JsonField.of("org_member")) - - val PROJECT_LOG = RestrictObjectType(JsonField.of("project_log")) - - val ORG_PROJECT = RestrictObjectType(JsonField.of("org_project")) + private val hashCode: Int by lazy { + Objects.hash(permission, restrictObjectType, additionalProperties) + } - fun of(value: String) = RestrictObjectType(JsonField.of(value)) - } + override fun hashCode(): Int = hashCode - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + override fun toString() = + "RemoveMemberPermission{permission=$permission, restrictObjectType=$restrictObjectType, additionalProperties=$additionalProperties}" + } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN - } + return other is RoleUpdateParams && + roleId == other.roleId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> - throw BraintrustInvalidDataException("Unknown RestrictObjectType: $value") - } + override fun hashCode(): Int = + Objects.hash(roleId, body, additionalHeaders, additionalQueryParams) - fun asString(): String = _value().asStringOrThrow() - } - } + override fun toString() = + "RoleUpdateParams{roleId=$roleId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ScoreSummary.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ScoreSummary.kt index 63528161..6672ce5f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ScoreSummary.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ScoreSummary.kt @@ -6,195 +6,321 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** Summary of a score's performance */ -@JsonDeserialize(builder = ScoreSummary.Builder::class) -@NoAutoDetect class ScoreSummary +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val improvements: JsonField, private val name: JsonField, + private val regressions: JsonField, private val score: JsonField, private val diff: JsonField, - private val improvements: JsonField, - private val regressions: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("improvements") + @ExcludeMissing + improvements: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("regressions") + @ExcludeMissing + regressions: JsonField = JsonMissing.of(), + @JsonProperty("score") @ExcludeMissing score: JsonField = JsonMissing.of(), + @JsonProperty("diff") @ExcludeMissing diff: JsonField = JsonMissing.of(), + ) : this(improvements, name, regressions, score, diff, mutableMapOf()) + + /** + * Number of improvements in the score + * + * @throws BraintrustInvalidDataException 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 improvements(): Long = improvements.getRequired("improvements") - /** Name of the score */ + /** + * Name of the score + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** Average score across all examples */ - fun score(): Double = score.getRequired("score") - - /** Difference in score between the current and comparison experiment */ - fun diff(): Double? = diff.getNullable("diff") - - /** Number of improvements in the score */ - fun improvements(): Long = improvements.getRequired("improvements") - - /** Number of regressions in the score */ + /** + * Number of regressions in the score + * + * @throws BraintrustInvalidDataException 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 regressions(): Long = regressions.getRequired("regressions") - /** Name of the score */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Average score across all examples */ - @JsonProperty("score") @ExcludeMissing fun _score() = score - - /** Difference in score between the current and comparison experiment */ - @JsonProperty("diff") @ExcludeMissing fun _diff() = diff + /** + * Average score across all examples + * + * @throws BraintrustInvalidDataException 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 score(): Double = score.getRequired("score") - /** Number of improvements in the score */ - @JsonProperty("improvements") @ExcludeMissing fun _improvements() = improvements + /** + * Difference in score between the current and comparison experiment + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun diff(): Double? = diff.getNullable("diff") - /** Number of regressions in the score */ - @JsonProperty("regressions") @ExcludeMissing fun _regressions() = regressions + /** + * Returns the raw JSON value of [improvements]. + * + * Unlike [improvements], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("improvements") + @ExcludeMissing + fun _improvements(): JsonField = improvements + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [regressions]. + * + * Unlike [regressions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("regressions") @ExcludeMissing fun _regressions(): JsonField = regressions + + /** + * Returns the raw JSON value of [score]. + * + * Unlike [score], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("score") @ExcludeMissing fun _score(): JsonField = score + + /** + * Returns the raw JSON value of [diff]. + * + * Unlike [diff], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("diff") @ExcludeMissing fun _diff(): JsonField = diff + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ScoreSummary = apply { - if (!validated) { - name() - score() - diff() - improvements() - regressions() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ScoreSummary && - this.name == other.name && - this.score == other.score && - this.diff == other.diff && - this.improvements == other.improvements && - this.regressions == other.regressions && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - score, - diff, - improvements, - regressions, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ScoreSummary{name=$name, score=$score, diff=$diff, improvements=$improvements, regressions=$regressions, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [ScoreSummary]. + * + * The following fields are required: + * ```kotlin + * .improvements() + * .name() + * .regressions() + * .score() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [ScoreSummary]. */ + class Builder internal constructor() { - private var name: JsonField = JsonMissing.of() - private var score: JsonField = JsonMissing.of() + private var improvements: JsonField? = null + private var name: JsonField? = null + private var regressions: JsonField? = null + private var score: JsonField? = null private var diff: JsonField = JsonMissing.of() - private var improvements: JsonField = JsonMissing.of() - private var regressions: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(scoreSummary: ScoreSummary) = apply { - this.name = scoreSummary.name - this.score = scoreSummary.score - this.diff = scoreSummary.diff - this.improvements = scoreSummary.improvements - this.regressions = scoreSummary.regressions - additionalProperties(scoreSummary.additionalProperties) + improvements = scoreSummary.improvements + name = scoreSummary.name + regressions = scoreSummary.regressions + score = scoreSummary.score + diff = scoreSummary.diff + additionalProperties = scoreSummary.additionalProperties.toMutableMap() } + /** Number of improvements in the score */ + fun improvements(improvements: Long) = improvements(JsonField.of(improvements)) + + /** + * Sets [Builder.improvements] to an arbitrary JSON value. + * + * You should usually call [Builder.improvements] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun improvements(improvements: JsonField) = apply { this.improvements = improvements } + /** Name of the score */ fun name(name: String) = name(JsonField.of(name)) - /** Name of the score */ - @JsonProperty("name") - @ExcludeMissing + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun name(name: JsonField) = apply { this.name = name } + /** Number of regressions in the score */ + fun regressions(regressions: Long) = regressions(JsonField.of(regressions)) + + /** + * Sets [Builder.regressions] to an arbitrary JSON value. + * + * You should usually call [Builder.regressions] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun regressions(regressions: JsonField) = apply { this.regressions = regressions } + /** Average score across all examples */ fun score(score: Double) = score(JsonField.of(score)) - /** Average score across all examples */ - @JsonProperty("score") - @ExcludeMissing + /** + * Sets [Builder.score] to an arbitrary JSON value. + * + * You should usually call [Builder.score] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun score(score: JsonField) = apply { this.score = score } /** Difference in score between the current and comparison experiment */ fun diff(diff: Double) = diff(JsonField.of(diff)) - /** Difference in score between the current and comparison experiment */ - @JsonProperty("diff") - @ExcludeMissing + /** + * Sets [Builder.diff] to an arbitrary JSON value. + * + * You should usually call [Builder.diff] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun diff(diff: JsonField) = apply { this.diff = diff } - /** Number of improvements in the score */ - fun improvements(improvements: Long) = improvements(JsonField.of(improvements)) - - /** Number of improvements in the score */ - @JsonProperty("improvements") - @ExcludeMissing - fun improvements(improvements: JsonField) = apply { this.improvements = improvements } - - /** Number of regressions in the score */ - fun regressions(regressions: Long) = regressions(JsonField.of(regressions)) - - /** Number of regressions in the score */ - @JsonProperty("regressions") - @ExcludeMissing - fun regressions(regressions: JsonField) = apply { this.regressions = regressions } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ScoreSummary]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .improvements() + * .name() + * .regressions() + * .score() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ScoreSummary = ScoreSummary( - name, - score, + checkRequired("improvements", improvements), + checkRequired("name", name), + checkRequired("regressions", regressions), + checkRequired("score", score), diff, - improvements, - regressions, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): ScoreSummary = apply { + if (validated) { + return@apply + } + + improvements() + name() + regressions() + score() + diff() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (improvements.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (regressions.asKnown() == null) 0 else 1) + + (if (score.asKnown() == null) 0 else 1) + + (if (diff.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ScoreSummary && + improvements == other.improvements && + name == other.name && + regressions == other.regressions && + score == other.score && + diff == other.diff && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(improvements, name, regressions, score, diff, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ScoreSummary{improvements=$improvements, name=$name, regressions=$regressions, score=$score, diff=$diff, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Scorer.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Scorer.kt deleted file mode 100644 index 311afc4e..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Scorer.kt +++ /dev/null @@ -1,182 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.databind.annotation.JsonDeserialize -import java.util.Objects - -@JsonDeserialize(builder = Scorer.Builder::class) -@NoAutoDetect -class Scorer -private constructor( - private val type: JsonField, - private val index: JsonField, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun type(): Type = type.getRequired("type") - - fun index(): Long = index.getRequired("index") - - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonProperty("index") @ExcludeMissing fun _index() = index - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Scorer = apply { - if (!validated) { - type() - index() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Scorer && - this.type == other.type && - this.index == other.index && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - index, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Scorer{type=$type, index=$index, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var type: JsonField = JsonMissing.of() - private var index: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(scorer: Scorer) = apply { - this.type = scorer.type - this.index = scorer.index - additionalProperties(scorer.additionalProperties) - } - - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun index(index: Long) = index(JsonField.of(index)) - - @JsonProperty("index") - @ExcludeMissing - fun index(index: JsonField) = apply { this.index = index } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Scorer = - Scorer( - type, - index, - additionalProperties.toUnmodifiable(), - ) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val SCORER = Type(JsonField.of("scorer")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - SCORER, - } - - enum class Value { - SCORER, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - SCORER -> Value.SCORER - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - SCORER -> Known.SCORER - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanAttributes.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanAttributes.kt new file mode 100644 index 00000000..4589264a --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanAttributes.kt @@ -0,0 +1,188 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 + +/** Human-identifying attributes of the span, such as name, type, etc. */ +class SpanAttributes +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val name: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(name, type, mutableMapOf()) + + /** + * Name of the span, for display purposes only + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * Type of the span, for display purposes only + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): SpanType? = type.getNullable("type") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [SpanAttributes]. */ + fun builder() = Builder() + } + + /** A builder for [SpanAttributes]. */ + class Builder internal constructor() { + + private var name: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(spanAttributes: SpanAttributes) = apply { + name = spanAttributes.name + type = spanAttributes.type + additionalProperties = spanAttributes.additionalProperties.toMutableMap() + } + + /** Name of the span, for display purposes only */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Type of the span, for display purposes only */ + fun type(type: SpanType?) = type(JsonField.ofNullable(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [SpanType] 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 [SpanAttributes]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SpanAttributes = + SpanAttributes(name, type, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SpanAttributes = apply { + if (validated) { + return@apply + } + + name() + type()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + (type.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanAttributes && + name == other.name && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(name, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SpanAttributes{name=$name, type=$type, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIFrame.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIFrame.kt new file mode 100644 index 00000000..71209d22 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIFrame.kt @@ -0,0 +1,504 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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.util.Collections +import java.util.Objects + +class SpanIFrame +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val name: JsonField, + private val projectId: JsonField, + private val url: JsonField, + private val created: JsonField, + private val deletedAt: JsonField, + private val description: JsonField, + private val postMessage: JsonField, + private val userId: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") @ExcludeMissing projectId: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("post_message") + @ExcludeMissing + postMessage: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + ) : this( + id, + name, + projectId, + url, + created, + deletedAt, + description, + postMessage, + userId, + mutableMapOf(), + ) + + /** + * Unique identifier for the span iframe + * + * @throws BraintrustInvalidDataException 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") + + /** + * Name of the span iframe + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the span iframe belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * URL to embed the project viewer in an iframe + * + * @throws BraintrustInvalidDataException 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") + + /** + * Date of span iframe creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun created(): OffsetDateTime? = created.getNullable("created") + + /** + * Date of span iframe deletion, or null if the span iframe is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") + + /** + * Textual description of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when you + * want to render more data than fits in the URL. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun postMessage(): Boolean? = postMessage.getNullable("post_message") + + /** + * Identifies the user who created the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [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 [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt + + /** + * 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 [postMessage]. + * + * Unlike [postMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("post_message") + @ExcludeMissing + fun _postMessage(): JsonField = postMessage + + /** + * Returns the raw JSON value of [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + @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 [SpanIFrame]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .url() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [SpanIFrame]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var name: JsonField? = null + private var projectId: JsonField? = null + private var url: JsonField? = null + private var created: JsonField = JsonMissing.of() + private var deletedAt: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var postMessage: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(spanIFrame: SpanIFrame) = apply { + id = spanIFrame.id + name = spanIFrame.name + projectId = spanIFrame.projectId + url = spanIFrame.url + created = spanIFrame.created + deletedAt = spanIFrame.deletedAt + description = spanIFrame.description + postMessage = spanIFrame.postMessage + userId = spanIFrame.userId + additionalProperties = spanIFrame.additionalProperties.toMutableMap() + } + + /** Unique identifier for the span iframe */ + 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 } + + /** Name of the span iframe */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Unique identifier for the project that the span iframe belongs under */ + 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 } + + /** URL to embed the project viewer in an iframe */ + 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 } + + /** Date of span iframe creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } + + /** Date of span iframe deletion, or null if the span iframe is still active */ + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } + + /** Textual description of the span iframe */ + fun description(description: String?) = description(JsonField.ofNullable(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 } + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when + * you want to render more data than fits in the URL. + */ + fun postMessage(postMessage: Boolean?) = postMessage(JsonField.ofNullable(postMessage)) + + /** + * Alias for [Builder.postMessage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun postMessage(postMessage: Boolean) = postMessage(postMessage as Boolean?) + + /** + * Sets [Builder.postMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.postMessage] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun postMessage(postMessage: JsonField) = apply { this.postMessage = postMessage } + + /** Identifies the user who created the span iframe */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } + + 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 [SpanIFrame]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .projectId() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanIFrame = + SpanIFrame( + checkRequired("id", id), + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("url", url), + created, + deletedAt, + description, + postMessage, + userId, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SpanIFrame = apply { + if (validated) { + return@apply + } + + id() + name() + projectId() + url() + created() + deletedAt() + description() + postMessage() + userId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (url.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (if (postMessage.asKnown() == null) 0 else 1) + + (if (userId.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIFrame && + id == other.id && + name == other.name && + projectId == other.projectId && + url == other.url && + created == other.created && + deletedAt == other.deletedAt && + description == other.description && + postMessage == other.postMessage && + userId == other.userId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + projectId, + url, + created, + deletedAt, + description, + postMessage, + userId, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SpanIFrame{id=$id, name=$name, projectId=$projectId, url=$url, created=$created, deletedAt=$deletedAt, description=$description, postMessage=$postMessage, userId=$userId, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeCreateParams.kt new file mode 100644 index 00000000..c07f6d71 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeCreateParams.kt @@ -0,0 +1,718 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 + +/** + * Create a new span_iframe. If there is an existing span_iframe with the same name as the one + * specified in the request, will return the existing span_iframe unmodified + */ +class SpanIframeCreateParams +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the span iframe + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the span iframe belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * URL to embed the project viewer in an iframe + * + * @throws BraintrustInvalidDataException 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() + + /** + * Textual description of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when you + * want to render more data than fits in the URL. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun postMessage(): Boolean? = body.postMessage() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [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 [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [postMessage]. + * + * Unlike [postMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _postMessage(): JsonField = body._postMessage() + + 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 [SpanIframeCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeCreateParams]. */ + 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() + + internal fun from(spanIframeCreateParams: SpanIframeCreateParams) = apply { + body = spanIframeCreateParams.body.toBuilder() + additionalHeaders = spanIframeCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = spanIframeCreateParams.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: + * - [name] + * - [projectId] + * - [url] + * - [description] + * - [postMessage] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Name of the span iframe */ + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + /** Unique identifier for the project that the span iframe belongs under */ + 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) } + + /** URL to embed the project viewer in an iframe */ + 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) } + + /** Textual description of the span iframe */ + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when + * you want to render more data than fits in the URL. + */ + fun postMessage(postMessage: Boolean?) = apply { body.postMessage(postMessage) } + + /** + * Alias for [Builder.postMessage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun postMessage(postMessage: Boolean) = postMessage(postMessage as Boolean?) + + /** + * Sets [Builder.postMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.postMessage] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun postMessage(postMessage: JsonField) = apply { body.postMessage(postMessage) } + + 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 [SpanIframeCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanIframeCreateParams = + SpanIframeCreateParams( + 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 name: JsonField, + private val projectId: JsonField, + private val url: JsonField, + private val description: JsonField, + private val postMessage: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("post_message") + @ExcludeMissing + postMessage: JsonField = JsonMissing.of(), + ) : this(name, projectId, url, description, postMessage, mutableMapOf()) + + /** + * Name of the span iframe + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the span iframe belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * URL to embed the project viewer in an iframe + * + * @throws BraintrustInvalidDataException 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") + + /** + * Textual description of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when + * you want to render more data than fits in the URL. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun postMessage(): Boolean? = postMessage.getNullable("post_message") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [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 [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 [postMessage]. + * + * Unlike [postMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("post_message") + @ExcludeMissing + fun _postMessage(): JsonField = postMessage + + @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: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var projectId: JsonField? = null + private var url: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var postMessage: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + url = body.url + description = body.description + postMessage = body.postMessage + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Name of the span iframe */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Unique identifier for the project that the span iframe belongs under */ + 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 } + + /** URL to embed the project viewer in an iframe */ + 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 } + + /** Textual description of the span iframe */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** + * Whether to post messages to the iframe containing the span's data. This is useful + * when you want to render more data than fits in the URL. + */ + fun postMessage(postMessage: Boolean?) = postMessage(JsonField.ofNullable(postMessage)) + + /** + * Alias for [Builder.postMessage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun postMessage(postMessage: Boolean) = postMessage(postMessage as Boolean?) + + /** + * Sets [Builder.postMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.postMessage] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun postMessage(postMessage: JsonField) = apply { + this.postMessage = postMessage + } + + 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: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("url", url), + description, + postMessage, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + projectId() + url() + description() + postMessage() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (url.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (if (postMessage.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + projectId == other.projectId && + url == other.url && + description == other.description && + postMessage == other.postMessage && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(name, projectId, url, description, postMessage, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, projectId=$projectId, url=$url, description=$description, postMessage=$postMessage, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIframeCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SpanIframeCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeDeleteParams.kt new file mode 100644 index 00000000..62dfda08 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeDeleteParams.kt @@ -0,0 +1,230 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import java.util.Objects + +/** Delete a span_iframe object by its id */ +class SpanIframeDeleteParams +private constructor( + private val spanIframeId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + /** SpanIframe id */ + fun spanIframeId(): String? = spanIframeId + + /** 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 { + + fun none(): SpanIframeDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SpanIframeDeleteParams]. */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeDeleteParams]. */ + class Builder internal constructor() { + + private var spanIframeId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + internal fun from(spanIframeDeleteParams: SpanIframeDeleteParams) = apply { + spanIframeId = spanIframeDeleteParams.spanIframeId + additionalHeaders = spanIframeDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = spanIframeDeleteParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + spanIframeDeleteParams.additionalBodyProperties.toMutableMap() + } + + /** SpanIframe id */ + fun spanIframeId(spanIframeId: String?) = apply { this.spanIframeId = spanIframeId } + + 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 [SpanIframeDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SpanIframeDeleteParams = + SpanIframeDeleteParams( + spanIframeId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Map? = additionalBodyProperties.ifEmpty { null } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> spanIframeId ?: "" + 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 SpanIframeDeleteParams && + spanIframeId == other.spanIframeId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash( + spanIframeId, + additionalHeaders, + additionalQueryParams, + additionalBodyProperties, + ) + + override fun toString() = + "SpanIframeDeleteParams{spanIframeId=$spanIframeId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPage.kt new file mode 100644 index 00000000..3c65539d --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPage.kt @@ -0,0 +1,122 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.services.blocking.SpanIframeService +import java.util.Objects + +/** @see SpanIframeService.list */ +class SpanIframeListPage +private constructor( + private val service: SpanIframeService, + private val params: SpanIframeListParams, + private val response: SpanIframeListPageResponse, +) : Page { + + /** + * Delegates to [SpanIframeListPageResponse], but gracefully handles missing data. + * + * @see SpanIframeListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() + + override fun items(): List = objects() + + override fun hasNextPage(): Boolean = items().isNotEmpty() + + fun nextPageParams(): SpanIframeListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() + } else { + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() + } + + override fun nextPage(): SpanIframeListPage = service.list(nextPageParams()) + + fun autoPager(): AutoPager = AutoPager.from(this) + + /** The parameters that were used to request this page. */ + fun params(): SpanIframeListParams = params + + /** The response that this page was parsed from. */ + fun response(): SpanIframeListPageResponse = response + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SpanIframeListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeListPage]. */ + class Builder internal constructor() { + + private var service: SpanIframeService? = null + private var params: SpanIframeListParams? = null + private var response: SpanIframeListPageResponse? = null + + internal fun from(spanIframeListPage: SpanIframeListPage) = apply { + service = spanIframeListPage.service + params = spanIframeListPage.params + response = spanIframeListPage.response + } + + fun service(service: SpanIframeService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: SpanIframeListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: SpanIframeListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [SpanIframeListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanIframeListPage = + SpanIframeListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIframeListPage && + service == other.service && + params == other.params && + response == other.response + } + + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "SpanIframeListPage{service=$service, params=$params, response=$response}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPageAsync.kt new file mode 100644 index 00000000..cf8c0601 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPageAsync.kt @@ -0,0 +1,122 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.services.async.SpanIframeServiceAsync +import java.util.Objects + +/** @see SpanIframeServiceAsync.list */ +class SpanIframeListPageAsync +private constructor( + private val service: SpanIframeServiceAsync, + private val params: SpanIframeListParams, + private val response: SpanIframeListPageResponse, +) : PageAsync { + + /** + * Delegates to [SpanIframeListPageResponse], but gracefully handles missing data. + * + * @see SpanIframeListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() + + override fun items(): List = objects() + + override fun hasNextPage(): Boolean = items().isNotEmpty() + + fun nextPageParams(): SpanIframeListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() + } else { + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() + } + + override suspend fun nextPage(): SpanIframeListPageAsync = service.list(nextPageParams()) + + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) + + /** The parameters that were used to request this page. */ + fun params(): SpanIframeListParams = params + + /** The response that this page was parsed from. */ + fun response(): SpanIframeListPageResponse = response + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SpanIframeListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeListPageAsync]. */ + class Builder internal constructor() { + + private var service: SpanIframeServiceAsync? = null + private var params: SpanIframeListParams? = null + private var response: SpanIframeListPageResponse? = null + + internal fun from(spanIframeListPageAsync: SpanIframeListPageAsync) = apply { + service = spanIframeListPageAsync.service + params = spanIframeListPageAsync.params + response = spanIframeListPageAsync.response + } + + fun service(service: SpanIframeServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: SpanIframeListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: SpanIframeListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [SpanIframeListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanIframeListPageAsync = + SpanIframeListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIframeListPageAsync && + service == other.service && + params == other.params && + response == other.response + } + + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "SpanIframeListPageAsync{service=$service, params=$params, response=$response}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPageResponse.kt new file mode 100644 index 00000000..a9a60fae --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListPageResponse.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 SpanIframeListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") + @ExcludeMissing + objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of span_iframe objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [SpanIframeListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(spanIframeListPageResponse: SpanIframeListPageResponse) = apply { + objects = spanIframeListPageResponse.objects.map { it.toMutableList() } + additionalProperties = spanIframeListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of span_iframe objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [SpanIFrame] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: SpanIFrame) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [SpanIframeListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanIframeListPageResponse = + SpanIframeListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SpanIframeListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIframeListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SpanIframeListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListParams.kt new file mode 100644 index 00000000..a90d2b68 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeListParams.kt @@ -0,0 +1,379 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.getOrThrow +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable +import java.util.Objects + +/** + * List out all span_iframes. The span_iframes are sorted by creation date, with the most + * recently-created span_iframes coming first + */ +class SpanIframeListParams +private constructor( + private val endingBefore: String?, + private val ids: Ids?, + private val limit: Long?, + private val orgName: String?, + private val spanIframeName: String?, + private val startingAfter: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ + fun endingBefore(): String? = endingBefore + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ + fun ids(): Ids? = ids + + /** Limit the number of objects to return */ + fun limit(): Long? = limit + + /** Filter search results to within a particular organization */ + fun orgName(): String? = orgName + + /** Name of the span_iframe to search for */ + fun spanIframeName(): String? = spanIframeName + + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ + fun startingAfter(): String? = startingAfter + + /** 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 { + + fun none(): SpanIframeListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SpanIframeListParams]. */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeListParams]. */ + class Builder internal constructor() { + + private var endingBefore: String? = null + private var ids: Ids? = null + private var limit: Long? = null + private var orgName: String? = null + private var spanIframeName: String? = null + private var startingAfter: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + internal fun from(spanIframeListParams: SpanIframeListParams) = apply { + endingBefore = spanIframeListParams.endingBefore + ids = spanIframeListParams.ids + limit = spanIframeListParams.limit + orgName = spanIframeListParams.orgName + spanIframeName = spanIframeListParams.spanIframeName + startingAfter = spanIframeListParams.startingAfter + additionalHeaders = spanIframeListParams.additionalHeaders.toBuilder() + additionalQueryParams = spanIframeListParams.additionalQueryParams.toBuilder() + } + + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, + * include the query param multiple times + */ + fun ids(ids: Ids?) = apply { this.ids = ids } + + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) + + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) + + /** Limit the number of objects to return */ + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** Filter search results to within a particular organization */ + fun orgName(orgName: String?) = apply { this.orgName = orgName } + + /** Name of the span_iframe to search for */ + fun spanIframeName(spanIframeName: String?) = apply { this.spanIframeName = spanIframeName } + + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } + + 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 [SpanIframeListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SpanIframeListParams = + SpanIframeListParams( + endingBefore, + ids, + limit, + orgName, + spanIframeName, + startingAfter, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + spanIframeName?.let { put("span_iframe_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ + class Ids + private constructor( + private val string: String? = null, + private val strings: List? = null, + ) { + + fun string(): String? = string + + fun strings(): List? = strings + + fun isString(): Boolean = string != null + + fun isStrings(): Boolean = strings != null + + fun asString(): String = string.getOrThrow("string") + + fun asStrings(): List = strings.getOrThrow("strings") + + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + strings != null -> visitor.visitStrings(strings) + else -> throw IllegalStateException("Invalid Ids") + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Ids && string == other.string && strings == other.strings + } + + override fun hashCode(): Int = Objects.hash(string, strings) + + override fun toString(): String = + when { + string != null -> "Ids{string=$string}" + strings != null -> "Ids{strings=$strings}" + else -> throw IllegalStateException("Invalid Ids") + } + + companion object { + + fun ofString(string: String) = Ids(string = string) + + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) + } + + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ + interface Visitor { + + fun visitString(string: String): T + + fun visitStrings(strings: List): T + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIframeListParams && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + spanIframeName == other.spanIframeName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + endingBefore, + ids, + limit, + orgName, + spanIframeName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "SpanIframeListParams{endingBefore=$endingBefore, ids=$ids, limit=$limit, orgName=$orgName, spanIframeName=$spanIframeName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeReplaceParams.kt new file mode 100644 index 00000000..a6ae7551 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeReplaceParams.kt @@ -0,0 +1,718 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 + +/** + * Create or replace span_iframe. If there is an existing span_iframe with the same name as the one + * specified in the request, will replace the existing span_iframe with the provided fields + */ +class SpanIframeReplaceParams +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the span iframe + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * Unique identifier for the project that the span iframe belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = body.projectId() + + /** + * URL to embed the project viewer in an iframe + * + * @throws BraintrustInvalidDataException 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() + + /** + * Textual description of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when you + * want to render more data than fits in the URL. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun postMessage(): Boolean? = body.postMessage() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [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 [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [postMessage]. + * + * Unlike [postMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _postMessage(): JsonField = body._postMessage() + + 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 [SpanIframeReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeReplaceParams]. */ + 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() + + internal fun from(spanIframeReplaceParams: SpanIframeReplaceParams) = apply { + body = spanIframeReplaceParams.body.toBuilder() + additionalHeaders = spanIframeReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = spanIframeReplaceParams.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: + * - [name] + * - [projectId] + * - [url] + * - [description] + * - [postMessage] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Name of the span iframe */ + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + /** Unique identifier for the project that the span iframe belongs under */ + 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) } + + /** URL to embed the project viewer in an iframe */ + 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) } + + /** Textual description of the span iframe */ + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when + * you want to render more data than fits in the URL. + */ + fun postMessage(postMessage: Boolean?) = apply { body.postMessage(postMessage) } + + /** + * Alias for [Builder.postMessage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun postMessage(postMessage: Boolean) = postMessage(postMessage as Boolean?) + + /** + * Sets [Builder.postMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.postMessage] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun postMessage(postMessage: JsonField) = apply { body.postMessage(postMessage) } + + 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 [SpanIframeReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SpanIframeReplaceParams = + SpanIframeReplaceParams( + 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 name: JsonField, + private val projectId: JsonField, + private val url: JsonField, + private val description: JsonField, + private val postMessage: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("post_message") + @ExcludeMissing + postMessage: JsonField = JsonMissing.of(), + ) : this(name, projectId, url, description, postMessage, mutableMapOf()) + + /** + * Name of the span iframe + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * Unique identifier for the project that the span iframe belongs under + * + * @throws BraintrustInvalidDataException 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 projectId(): String = projectId.getRequired("project_id") + + /** + * URL to embed the project viewer in an iframe + * + * @throws BraintrustInvalidDataException 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") + + /** + * Textual description of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when + * you want to render more data than fits in the URL. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun postMessage(): Boolean? = postMessage.getNullable("post_message") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [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 [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 [postMessage]. + * + * Unlike [postMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("post_message") + @ExcludeMissing + fun _postMessage(): JsonField = postMessage + + @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: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var projectId: JsonField? = null + private var url: JsonField? = null + private var description: JsonField = JsonMissing.of() + private var postMessage: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + name = body.name + projectId = body.projectId + url = body.url + description = body.description + postMessage = body.postMessage + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Name of the span iframe */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** Unique identifier for the project that the span iframe belongs under */ + 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 } + + /** URL to embed the project viewer in an iframe */ + 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 } + + /** Textual description of the span iframe */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** + * Whether to post messages to the iframe containing the span's data. This is useful + * when you want to render more data than fits in the URL. + */ + fun postMessage(postMessage: Boolean?) = postMessage(JsonField.ofNullable(postMessage)) + + /** + * Alias for [Builder.postMessage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun postMessage(postMessage: Boolean) = postMessage(postMessage as Boolean?) + + /** + * Sets [Builder.postMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.postMessage] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun postMessage(postMessage: JsonField) = apply { + this.postMessage = postMessage + } + + 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: + * ```kotlin + * .name() + * .projectId() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("projectId", projectId), + checkRequired("url", url), + description, + postMessage, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + name() + projectId() + url() + description() + postMessage() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (projectId.asKnown() == null) 0 else 1) + + (if (url.asKnown() == null) 0 else 1) + + (if (description.asKnown() == null) 0 else 1) + + (if (postMessage.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + name == other.name && + projectId == other.projectId && + url == other.url && + description == other.description && + postMessage == other.postMessage && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(name, projectId, url, description, postMessage, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, projectId=$projectId, url=$url, description=$description, postMessage=$postMessage, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIframeReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SpanIframeReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeRetrieveParams.kt new file mode 100644 index 00000000..fa6b17d6 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeRetrieveParams.kt @@ -0,0 +1,190 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import java.util.Objects + +/** Get a span_iframe object by its id */ +class SpanIframeRetrieveParams +private constructor( + private val spanIframeId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** SpanIframe id */ + fun spanIframeId(): String? = spanIframeId + + /** 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 { + + fun none(): SpanIframeRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SpanIframeRetrieveParams]. */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeRetrieveParams]. */ + class Builder internal constructor() { + + private var spanIframeId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + internal fun from(spanIframeRetrieveParams: SpanIframeRetrieveParams) = apply { + spanIframeId = spanIframeRetrieveParams.spanIframeId + additionalHeaders = spanIframeRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = spanIframeRetrieveParams.additionalQueryParams.toBuilder() + } + + /** SpanIframe id */ + fun spanIframeId(spanIframeId: String?) = apply { this.spanIframeId = spanIframeId } + + 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 [SpanIframeRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SpanIframeRetrieveParams = + SpanIframeRetrieveParams( + spanIframeId, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> spanIframeId ?: "" + 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 SpanIframeRetrieveParams && + spanIframeId == other.spanIframeId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(spanIframeId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SpanIframeRetrieveParams{spanIframeId=$spanIframeId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeUpdateParams.kt new file mode 100644 index 00000000..b17c432b --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanIframeUpdateParams.kt @@ -0,0 +1,630 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 + +/** + * Partially update a span_iframe object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ +class SpanIframeUpdateParams +private constructor( + private val spanIframeId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** SpanIframe id */ + fun spanIframeId(): String? = spanIframeId + + /** + * Textual description of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun description(): String? = body.description() + + /** + * Name of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when you + * want to render more data than fits in the URL. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun postMessage(): Boolean? = body.postMessage() + + /** + * URL to embed the project viewer in an iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun url(): String? = body.url() + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _description(): JsonField = body._description() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [postMessage]. + * + * Unlike [postMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _postMessage(): JsonField = body._postMessage() + + /** + * 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() + + 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 { + + fun none(): SpanIframeUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SpanIframeUpdateParams]. */ + fun builder() = Builder() + } + + /** A builder for [SpanIframeUpdateParams]. */ + class Builder internal constructor() { + + private var spanIframeId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + internal fun from(spanIframeUpdateParams: SpanIframeUpdateParams) = apply { + spanIframeId = spanIframeUpdateParams.spanIframeId + body = spanIframeUpdateParams.body.toBuilder() + additionalHeaders = spanIframeUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = spanIframeUpdateParams.additionalQueryParams.toBuilder() + } + + /** SpanIframe id */ + fun spanIframeId(spanIframeId: String?) = apply { this.spanIframeId = spanIframeId } + + /** + * 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: + * - [description] + * - [name] + * - [postMessage] + * - [url] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Textual description of the span iframe */ + fun description(description: String?) = apply { body.description(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 { body.description(description) } + + /** Name of the span iframe */ + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when + * you want to render more data than fits in the URL. + */ + fun postMessage(postMessage: Boolean?) = apply { body.postMessage(postMessage) } + + /** + * Alias for [Builder.postMessage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun postMessage(postMessage: Boolean) = postMessage(postMessage as Boolean?) + + /** + * Sets [Builder.postMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.postMessage] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun postMessage(postMessage: JsonField) = apply { body.postMessage(postMessage) } + + /** URL to embed the project viewer in an iframe */ + 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 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 [SpanIframeUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SpanIframeUpdateParams = + SpanIframeUpdateParams( + spanIframeId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> spanIframeId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val name: JsonField, + private val postMessage: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("post_message") + @ExcludeMissing + postMessage: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(description, name, postMessage, url, mutableMapOf()) + + /** + * Textual description of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): String? = description.getNullable("description") + + /** + * Name of the span iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * Whether to post messages to the iframe containing the span's data. This is useful when + * you want to render more data than fits in the URL. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun postMessage(): Boolean? = postMessage.getNullable("post_message") + + /** + * URL to embed the project viewer in an iframe + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun url(): String? = url.getNullable("url") + + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [postMessage]. + * + * Unlike [postMessage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("post_message") + @ExcludeMissing + fun _postMessage(): JsonField = postMessage + + /** + * 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 [Body]. */ + fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var description: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var postMessage: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(body: Body) = apply { + description = body.description + name = body.name + postMessage = body.postMessage + url = body.url + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Textual description of the span iframe */ + fun description(description: String?) = description(JsonField.ofNullable(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 + } + + /** Name of the span iframe */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Whether to post messages to the iframe containing the span's data. This is useful + * when you want to render more data than fits in the URL. + */ + fun postMessage(postMessage: Boolean?) = postMessage(JsonField.ofNullable(postMessage)) + + /** + * Alias for [Builder.postMessage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun postMessage(postMessage: Boolean) = postMessage(postMessage as Boolean?) + + /** + * Sets [Builder.postMessage] to an arbitrary JSON value. + * + * You should usually call [Builder.postMessage] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun postMessage(postMessage: JsonField) = apply { + this.postMessage = postMessage + } + + /** URL to embed the project viewer in an iframe */ + fun url(url: String?) = url(JsonField.ofNullable(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 [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body(description, name, postMessage, url, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + description() + name() + postMessage() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (description.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (postMessage.asKnown() == null) 0 else 1) + + (if (url.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + description == other.description && + name == other.name && + postMessage == other.postMessage && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(description, name, postMessage, url, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{description=$description, name=$name, postMessage=$postMessage, url=$url, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SpanIframeUpdateParams && + spanIframeId == other.spanIframeId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(spanIframeId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SpanIframeUpdateParams{spanIframeId=$spanIframeId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanType.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanType.kt new file mode 100644 index 00000000..e1928254 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SpanType.kt @@ -0,0 +1,156 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Enum +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.errors.BraintrustInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator + +/** Type of the span, for display purposes only */ +class SpanType @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 { + + val LLM = of("llm") + + val SCORE = of("score") + + val FUNCTION = of("function") + + val EVAL = of("eval") + + val TASK = of("task") + + val TOOL = of("tool") + + fun of(value: String) = SpanType(JsonField.of(value)) + } + + /** An enum containing [SpanType]'s known values. */ + enum class Known { + LLM, + SCORE, + FUNCTION, + EVAL, + TASK, + TOOL, + } + + /** + * An enum containing [SpanType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [SpanType] 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 { + LLM, + SCORE, + FUNCTION, + EVAL, + TASK, + TOOL, + /** An enum member indicating that [SpanType] 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) { + LLM -> Value.LLM + SCORE -> Value.SCORE + FUNCTION -> Value.FUNCTION + EVAL -> Value.EVAL + TASK -> Value.TASK + TOOL -> Value.TOOL + 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + LLM -> Known.LLM + SCORE -> Known.SCORE + FUNCTION -> Known.FUNCTION + EVAL -> Known.EVAL + TASK -> Known.TASK + TOOL -> Known.TOOL + else -> throw BraintrustInvalidDataException("Unknown SpanType: $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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): SpanType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + 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 SpanType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponse.kt index a97c8dc3..14ceb844 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponse.kt @@ -6,197 +6,343 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** Summary of a dataset */ -@JsonDeserialize(builder = SummarizeDatasetResponse.Builder::class) -@NoAutoDetect class SummarizeDatasetResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val projectName: JsonField, private val datasetName: JsonField, - private val projectUrl: JsonField, private val datasetUrl: JsonField, + private val projectName: JsonField, + private val projectUrl: JsonField, private val dataSummary: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("dataset_name") + @ExcludeMissing + datasetName: JsonField = JsonMissing.of(), + @JsonProperty("dataset_url") + @ExcludeMissing + datasetUrl: JsonField = JsonMissing.of(), + @JsonProperty("project_name") + @ExcludeMissing + projectName: JsonField = JsonMissing.of(), + @JsonProperty("project_url") + @ExcludeMissing + projectUrl: JsonField = JsonMissing.of(), + @JsonProperty("data_summary") + @ExcludeMissing + dataSummary: JsonField = JsonMissing.of(), + ) : this(datasetName, datasetUrl, projectName, projectUrl, dataSummary, mutableMapOf()) + + /** + * Name of the dataset + * + * @throws BraintrustInvalidDataException 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 datasetName(): String = datasetName.getRequired("dataset_name") - private var hashCode: Int = 0 + /** + * URL to the dataset's page in the Braintrust app + * + * @throws BraintrustInvalidDataException 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 datasetUrl(): String = datasetUrl.getRequired("dataset_url") - /** Name of the project that the dataset belongs to */ + /** + * Name of the project that the dataset belongs to + * + * @throws BraintrustInvalidDataException 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 projectName(): String = projectName.getRequired("project_name") - /** Name of the dataset */ - fun datasetName(): String = datasetName.getRequired("dataset_name") - - /** URL to the project's page in the Braintrust app */ + /** + * URL to the project's page in the Braintrust app + * + * @throws BraintrustInvalidDataException 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 projectUrl(): String = projectUrl.getRequired("project_url") - /** URL to the dataset's page in the Braintrust app */ - fun datasetUrl(): String = datasetUrl.getRequired("dataset_url") - - /** Summary of a dataset's data */ + /** + * Summary of a dataset's data + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun dataSummary(): DataSummary? = dataSummary.getNullable("data_summary") - /** Name of the project that the dataset belongs to */ - @JsonProperty("project_name") @ExcludeMissing fun _projectName() = projectName - - /** Name of the dataset */ - @JsonProperty("dataset_name") @ExcludeMissing fun _datasetName() = datasetName - - /** URL to the project's page in the Braintrust app */ - @JsonProperty("project_url") @ExcludeMissing fun _projectUrl() = projectUrl - - /** URL to the dataset's page in the Braintrust app */ - @JsonProperty("dataset_url") @ExcludeMissing fun _datasetUrl() = datasetUrl + /** + * Returns the raw JSON value of [datasetName]. + * + * Unlike [datasetName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dataset_name") + @ExcludeMissing + fun _datasetName(): JsonField = datasetName + + /** + * Returns the raw JSON value of [datasetUrl]. + * + * Unlike [datasetUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dataset_url") @ExcludeMissing fun _datasetUrl(): JsonField = datasetUrl + + /** + * Returns the raw JSON value of [projectName]. + * + * Unlike [projectName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("project_name") + @ExcludeMissing + fun _projectName(): JsonField = projectName + + /** + * Returns the raw JSON value of [projectUrl]. + * + * Unlike [projectUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("project_url") @ExcludeMissing fun _projectUrl(): JsonField = projectUrl + + /** + * Returns the raw JSON value of [dataSummary]. + * + * Unlike [dataSummary], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data_summary") + @ExcludeMissing + fun _dataSummary(): JsonField = dataSummary - /** Summary of a dataset's data */ - @JsonProperty("data_summary") @ExcludeMissing fun _dataSummary() = dataSummary + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): SummarizeDatasetResponse = apply { - if (!validated) { - projectName() - datasetName() - projectUrl() - datasetUrl() - dataSummary()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SummarizeDatasetResponse && - this.projectName == other.projectName && - this.datasetName == other.datasetName && - this.projectUrl == other.projectUrl && - this.datasetUrl == other.datasetUrl && - this.dataSummary == other.dataSummary && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - projectName, - datasetName, - projectUrl, - datasetUrl, - dataSummary, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SummarizeDatasetResponse{projectName=$projectName, datasetName=$datasetName, projectUrl=$projectUrl, datasetUrl=$datasetUrl, dataSummary=$dataSummary, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [SummarizeDatasetResponse]. + * + * The following fields are required: + * ```kotlin + * .datasetName() + * .datasetUrl() + * .projectName() + * .projectUrl() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [SummarizeDatasetResponse]. */ + class Builder internal constructor() { - private var projectName: JsonField = JsonMissing.of() - private var datasetName: JsonField = JsonMissing.of() - private var projectUrl: JsonField = JsonMissing.of() - private var datasetUrl: JsonField = JsonMissing.of() + private var datasetName: JsonField? = null + private var datasetUrl: JsonField? = null + private var projectName: JsonField? = null + private var projectUrl: JsonField? = null private var dataSummary: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(summarizeDatasetResponse: SummarizeDatasetResponse) = apply { - this.projectName = summarizeDatasetResponse.projectName - this.datasetName = summarizeDatasetResponse.datasetName - this.projectUrl = summarizeDatasetResponse.projectUrl - this.datasetUrl = summarizeDatasetResponse.datasetUrl - this.dataSummary = summarizeDatasetResponse.dataSummary - additionalProperties(summarizeDatasetResponse.additionalProperties) + datasetName = summarizeDatasetResponse.datasetName + datasetUrl = summarizeDatasetResponse.datasetUrl + projectName = summarizeDatasetResponse.projectName + projectUrl = summarizeDatasetResponse.projectUrl + dataSummary = summarizeDatasetResponse.dataSummary + additionalProperties = summarizeDatasetResponse.additionalProperties.toMutableMap() } - /** Name of the project that the dataset belongs to */ - fun projectName(projectName: String) = projectName(JsonField.of(projectName)) - - /** Name of the project that the dataset belongs to */ - @JsonProperty("project_name") - @ExcludeMissing - fun projectName(projectName: JsonField) = apply { this.projectName = projectName } - /** Name of the dataset */ fun datasetName(datasetName: String) = datasetName(JsonField.of(datasetName)) - /** Name of the dataset */ - @JsonProperty("dataset_name") - @ExcludeMissing + /** + * Sets [Builder.datasetName] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun datasetName(datasetName: JsonField) = apply { this.datasetName = datasetName } - /** URL to the project's page in the Braintrust app */ - fun projectUrl(projectUrl: String) = projectUrl(JsonField.of(projectUrl)) - - /** URL to the project's page in the Braintrust app */ - @JsonProperty("project_url") - @ExcludeMissing - fun projectUrl(projectUrl: JsonField) = apply { this.projectUrl = projectUrl } - /** URL to the dataset's page in the Braintrust app */ fun datasetUrl(datasetUrl: String) = datasetUrl(JsonField.of(datasetUrl)) - /** URL to the dataset's page in the Braintrust app */ - @JsonProperty("dataset_url") - @ExcludeMissing + /** + * Sets [Builder.datasetUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.datasetUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun datasetUrl(datasetUrl: JsonField) = apply { this.datasetUrl = datasetUrl } - /** Summary of a dataset's data */ - fun dataSummary(dataSummary: DataSummary) = dataSummary(JsonField.of(dataSummary)) + /** Name of the project that the dataset belongs to */ + fun projectName(projectName: String) = projectName(JsonField.of(projectName)) + + /** + * Sets [Builder.projectName] to an arbitrary JSON value. + * + * You should usually call [Builder.projectName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun projectName(projectName: JsonField) = apply { this.projectName = projectName } + + /** URL to the project's page in the Braintrust app */ + fun projectUrl(projectUrl: String) = projectUrl(JsonField.of(projectUrl)) + + /** + * Sets [Builder.projectUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.projectUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun projectUrl(projectUrl: JsonField) = apply { this.projectUrl = projectUrl } /** Summary of a dataset's data */ - @JsonProperty("data_summary") - @ExcludeMissing + fun dataSummary(dataSummary: DataSummary?) = dataSummary(JsonField.ofNullable(dataSummary)) + + /** + * Sets [Builder.dataSummary] to an arbitrary JSON value. + * + * You should usually call [Builder.dataSummary] with a well-typed [DataSummary] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun dataSummary(dataSummary: JsonField) = apply { this.dataSummary = dataSummary } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [SummarizeDatasetResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .datasetName() + * .datasetUrl() + * .projectName() + * .projectUrl() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): SummarizeDatasetResponse = SummarizeDatasetResponse( - projectName, - datasetName, - projectUrl, - datasetUrl, + checkRequired("datasetName", datasetName), + checkRequired("datasetUrl", datasetUrl), + checkRequired("projectName", projectName), + checkRequired("projectUrl", projectUrl), dataSummary, - additionalProperties.toUnmodifiable(), + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): SummarizeDatasetResponse = apply { + if (validated) { + return@apply + } + + datasetName() + datasetUrl() + projectName() + projectUrl() + dataSummary()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (datasetName.asKnown() == null) 0 else 1) + + (if (datasetUrl.asKnown() == null) 0 else 1) + + (if (projectName.asKnown() == null) 0 else 1) + + (if (projectUrl.asKnown() == null) 0 else 1) + + (dataSummary.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SummarizeDatasetResponse && + datasetName == other.datasetName && + datasetUrl == other.datasetUrl && + projectName == other.projectName && + projectUrl == other.projectUrl && + dataSummary == other.dataSummary && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + datasetName, + datasetUrl, + projectName, + projectUrl, + dataSummary, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SummarizeDatasetResponse{datasetName=$datasetName, datasetUrl=$datasetUrl, projectName=$projectName, projectUrl=$projectUrl, dataSummary=$dataSummary, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponse.kt index 0707694b..4107b1b1 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponse.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponse.kt @@ -6,391 +6,628 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** Summary of an experiment */ -@JsonDeserialize(builder = SummarizeExperimentResponse.Builder::class) -@NoAutoDetect class SummarizeExperimentResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val projectName: JsonField, private val experimentName: JsonField, - private val projectUrl: JsonField, private val experimentUrl: JsonField, + private val projectName: JsonField, + private val projectUrl: JsonField, private val comparisonExperimentName: JsonField, - private val scores: JsonField, private val metrics: JsonField, - private val additionalProperties: Map, + private val scores: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false + @JsonCreator + private constructor( + @JsonProperty("experiment_name") + @ExcludeMissing + experimentName: JsonField = JsonMissing.of(), + @JsonProperty("experiment_url") + @ExcludeMissing + experimentUrl: JsonField = JsonMissing.of(), + @JsonProperty("project_name") + @ExcludeMissing + projectName: JsonField = JsonMissing.of(), + @JsonProperty("project_url") + @ExcludeMissing + projectUrl: JsonField = JsonMissing.of(), + @JsonProperty("comparison_experiment_name") + @ExcludeMissing + comparisonExperimentName: JsonField = JsonMissing.of(), + @JsonProperty("metrics") @ExcludeMissing metrics: JsonField = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + ) : this( + experimentName, + experimentUrl, + projectName, + projectUrl, + comparisonExperimentName, + metrics, + scores, + mutableMapOf(), + ) + + /** + * Name of the experiment + * + * @throws BraintrustInvalidDataException 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 experimentName(): String = experimentName.getRequired("experiment_name") - private var hashCode: Int = 0 + /** + * URL to the experiment's page in the Braintrust app + * + * @throws BraintrustInvalidDataException 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 experimentUrl(): String = experimentUrl.getRequired("experiment_url") - /** Name of the project that the experiment belongs to */ + /** + * Name of the project that the experiment belongs to + * + * @throws BraintrustInvalidDataException 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 projectName(): String = projectName.getRequired("project_name") - /** Name of the experiment */ - fun experimentName(): String = experimentName.getRequired("experiment_name") - - /** URL to the project's page in the Braintrust app */ + /** + * URL to the project's page in the Braintrust app + * + * @throws BraintrustInvalidDataException 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 projectUrl(): String = projectUrl.getRequired("project_url") - /** URL to the experiment's page in the Braintrust app */ - fun experimentUrl(): String = experimentUrl.getRequired("experiment_url") - - /** The experiment which scores are baselined against */ + /** + * The experiment which scores are baselined against + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun comparisonExperimentName(): String? = comparisonExperimentName.getNullable("comparison_experiment_name") - /** Summary of the experiment's scores */ - fun scores(): Scores? = scores.getNullable("scores") - - /** Summary of the experiment's metrics */ + /** + * Summary of the experiment's metrics + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun metrics(): Metrics? = metrics.getNullable("metrics") - /** Name of the project that the experiment belongs to */ - @JsonProperty("project_name") @ExcludeMissing fun _projectName() = projectName - - /** Name of the experiment */ - @JsonProperty("experiment_name") @ExcludeMissing fun _experimentName() = experimentName - - /** URL to the project's page in the Braintrust app */ - @JsonProperty("project_url") @ExcludeMissing fun _projectUrl() = projectUrl - - /** URL to the experiment's page in the Braintrust app */ - @JsonProperty("experiment_url") @ExcludeMissing fun _experimentUrl() = experimentUrl + /** + * Summary of the experiment's scores + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun scores(): Scores? = scores.getNullable("scores") - /** The experiment which scores are baselined against */ + /** + * Returns the raw JSON value of [experimentName]. + * + * Unlike [experimentName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("experiment_name") + @ExcludeMissing + fun _experimentName(): JsonField = experimentName + + /** + * Returns the raw JSON value of [experimentUrl]. + * + * Unlike [experimentUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("experiment_url") + @ExcludeMissing + fun _experimentUrl(): JsonField = experimentUrl + + /** + * Returns the raw JSON value of [projectName]. + * + * Unlike [projectName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("project_name") + @ExcludeMissing + fun _projectName(): JsonField = projectName + + /** + * Returns the raw JSON value of [projectUrl]. + * + * Unlike [projectUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("project_url") @ExcludeMissing fun _projectUrl(): JsonField = projectUrl + + /** + * Returns the raw JSON value of [comparisonExperimentName]. + * + * Unlike [comparisonExperimentName], this method doesn't throw if the JSON field has an + * unexpected type. + */ @JsonProperty("comparison_experiment_name") @ExcludeMissing - fun _comparisonExperimentName() = comparisonExperimentName - - /** Summary of the experiment's scores */ - @JsonProperty("scores") @ExcludeMissing fun _scores() = scores - - /** Summary of the experiment's metrics */ - @JsonProperty("metrics") @ExcludeMissing fun _metrics() = metrics + fun _comparisonExperimentName(): JsonField = comparisonExperimentName + + /** + * Returns the raw JSON value of [metrics]. + * + * Unlike [metrics], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metrics") @ExcludeMissing fun _metrics(): JsonField = metrics + + /** + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): SummarizeExperimentResponse = apply { - if (!validated) { - projectName() - experimentName() - projectUrl() - experimentUrl() - comparisonExperimentName() - scores()?.validate() - metrics()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SummarizeExperimentResponse && - this.projectName == other.projectName && - this.experimentName == other.experimentName && - this.projectUrl == other.projectUrl && - this.experimentUrl == other.experimentUrl && - this.comparisonExperimentName == other.comparisonExperimentName && - this.scores == other.scores && - this.metrics == other.metrics && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - projectName, - experimentName, - projectUrl, - experimentUrl, - comparisonExperimentName, - scores, - metrics, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "SummarizeExperimentResponse{projectName=$projectName, experimentName=$experimentName, projectUrl=$projectUrl, experimentUrl=$experimentUrl, comparisonExperimentName=$comparisonExperimentName, scores=$scores, metrics=$metrics, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [SummarizeExperimentResponse]. + * + * The following fields are required: + * ```kotlin + * .experimentName() + * .experimentUrl() + * .projectName() + * .projectUrl() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [SummarizeExperimentResponse]. */ + class Builder internal constructor() { - private var projectName: JsonField = JsonMissing.of() - private var experimentName: JsonField = JsonMissing.of() - private var projectUrl: JsonField = JsonMissing.of() - private var experimentUrl: JsonField = JsonMissing.of() + private var experimentName: JsonField? = null + private var experimentUrl: JsonField? = null + private var projectName: JsonField? = null + private var projectUrl: JsonField? = null private var comparisonExperimentName: JsonField = JsonMissing.of() - private var scores: JsonField = JsonMissing.of() private var metrics: JsonField = JsonMissing.of() + private var scores: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(summarizeExperimentResponse: SummarizeExperimentResponse) = apply { - this.projectName = summarizeExperimentResponse.projectName - this.experimentName = summarizeExperimentResponse.experimentName - this.projectUrl = summarizeExperimentResponse.projectUrl - this.experimentUrl = summarizeExperimentResponse.experimentUrl - this.comparisonExperimentName = summarizeExperimentResponse.comparisonExperimentName - this.scores = summarizeExperimentResponse.scores - this.metrics = summarizeExperimentResponse.metrics - additionalProperties(summarizeExperimentResponse.additionalProperties) + experimentName = summarizeExperimentResponse.experimentName + experimentUrl = summarizeExperimentResponse.experimentUrl + projectName = summarizeExperimentResponse.projectName + projectUrl = summarizeExperimentResponse.projectUrl + comparisonExperimentName = summarizeExperimentResponse.comparisonExperimentName + metrics = summarizeExperimentResponse.metrics + scores = summarizeExperimentResponse.scores + additionalProperties = summarizeExperimentResponse.additionalProperties.toMutableMap() } - /** Name of the project that the experiment belongs to */ - fun projectName(projectName: String) = projectName(JsonField.of(projectName)) - - /** Name of the project that the experiment belongs to */ - @JsonProperty("project_name") - @ExcludeMissing - fun projectName(projectName: JsonField) = apply { this.projectName = projectName } - /** Name of the experiment */ fun experimentName(experimentName: String) = experimentName(JsonField.of(experimentName)) - /** Name of the experiment */ - @JsonProperty("experiment_name") - @ExcludeMissing + /** + * Sets [Builder.experimentName] to an arbitrary JSON value. + * + * You should usually call [Builder.experimentName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun experimentName(experimentName: JsonField) = apply { this.experimentName = experimentName } - /** URL to the project's page in the Braintrust app */ - fun projectUrl(projectUrl: String) = projectUrl(JsonField.of(projectUrl)) - - /** URL to the project's page in the Braintrust app */ - @JsonProperty("project_url") - @ExcludeMissing - fun projectUrl(projectUrl: JsonField) = apply { this.projectUrl = projectUrl } - /** URL to the experiment's page in the Braintrust app */ fun experimentUrl(experimentUrl: String) = experimentUrl(JsonField.of(experimentUrl)) - /** URL to the experiment's page in the Braintrust app */ - @JsonProperty("experiment_url") - @ExcludeMissing + /** + * Sets [Builder.experimentUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.experimentUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun experimentUrl(experimentUrl: JsonField) = apply { this.experimentUrl = experimentUrl } - /** The experiment which scores are baselined against */ - fun comparisonExperimentName(comparisonExperimentName: String) = - comparisonExperimentName(JsonField.of(comparisonExperimentName)) + /** Name of the project that the experiment belongs to */ + fun projectName(projectName: String) = projectName(JsonField.of(projectName)) + + /** + * Sets [Builder.projectName] to an arbitrary JSON value. + * + * You should usually call [Builder.projectName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun projectName(projectName: JsonField) = apply { this.projectName = projectName } + + /** URL to the project's page in the Braintrust app */ + fun projectUrl(projectUrl: String) = projectUrl(JsonField.of(projectUrl)) + + /** + * Sets [Builder.projectUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.projectUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun projectUrl(projectUrl: JsonField) = apply { this.projectUrl = projectUrl } /** The experiment which scores are baselined against */ - @JsonProperty("comparison_experiment_name") - @ExcludeMissing + fun comparisonExperimentName(comparisonExperimentName: String?) = + comparisonExperimentName(JsonField.ofNullable(comparisonExperimentName)) + + /** + * Sets [Builder.comparisonExperimentName] to an arbitrary JSON value. + * + * You should usually call [Builder.comparisonExperimentName] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ fun comparisonExperimentName(comparisonExperimentName: JsonField) = apply { this.comparisonExperimentName = comparisonExperimentName } - /** Summary of the experiment's scores */ - fun scores(scores: Scores) = scores(JsonField.of(scores)) + /** Summary of the experiment's metrics */ + fun metrics(metrics: Metrics?) = metrics(JsonField.ofNullable(metrics)) + + /** + * Sets [Builder.metrics] to an arbitrary JSON value. + * + * You should usually call [Builder.metrics] with a well-typed [Metrics] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun metrics(metrics: JsonField) = apply { this.metrics = metrics } /** Summary of the experiment's scores */ - @JsonProperty("scores") - @ExcludeMissing + fun scores(scores: Scores?) = scores(JsonField.ofNullable(scores)) + + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun scores(scores: JsonField) = apply { this.scores = scores } - /** Summary of the experiment's metrics */ - fun metrics(metrics: Metrics) = metrics(JsonField.of(metrics)) - - /** Summary of the experiment's metrics */ - @JsonProperty("metrics") - @ExcludeMissing - fun metrics(metrics: JsonField) = apply { this.metrics = metrics } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [SummarizeExperimentResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .experimentName() + * .experimentUrl() + * .projectName() + * .projectUrl() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): SummarizeExperimentResponse = SummarizeExperimentResponse( - projectName, - experimentName, - projectUrl, - experimentUrl, + checkRequired("experimentName", experimentName), + checkRequired("experimentUrl", experimentUrl), + checkRequired("projectName", projectName), + checkRequired("projectUrl", projectUrl), comparisonExperimentName, - scores, metrics, - additionalProperties.toUnmodifiable(), + scores, + additionalProperties.toMutableMap(), ) } + private var validated: Boolean = false + + fun validate(): SummarizeExperimentResponse = apply { + if (validated) { + return@apply + } + + experimentName() + experimentUrl() + projectName() + projectUrl() + comparisonExperimentName() + metrics()?.validate() + scores()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (experimentName.asKnown() == null) 0 else 1) + + (if (experimentUrl.asKnown() == null) 0 else 1) + + (if (projectName.asKnown() == null) 0 else 1) + + (if (projectUrl.asKnown() == null) 0 else 1) + + (if (comparisonExperimentName.asKnown() == null) 0 else 1) + + (metrics.asKnown()?.validity() ?: 0) + + (scores.asKnown()?.validity() ?: 0) + /** Summary of the experiment's metrics */ - @JsonDeserialize(builder = Metrics.Builder::class) - @NoAutoDetect class Metrics + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): Metrics = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Metrics && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "Metrics{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [Metrics]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Metrics]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(metrics: Metrics) = apply { - additionalProperties(metrics.additionalProperties) + additionalProperties = metrics.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Metrics = Metrics(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - /** Summary of the experiment's scores */ - @JsonDeserialize(builder = Scores.Builder::class) - @NoAutoDetect - class Scores - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Metrics]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Metrics = Metrics(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): Metrics = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): Scores = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Scores && this.additionalProperties == other.additionalProperties + return other is Metrics && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "Scores{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = "Metrics{additionalProperties=$additionalProperties}" + } + + /** Summary of the experiment's scores */ + class Scores + @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 [Scores]. */ fun builder() = Builder() } - class Builder { + /** A builder for [Scores]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(scores: Scores) = apply { - additionalProperties(scores.additionalProperties) + additionalProperties = scores.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Scores = Scores(additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) } + + private var validated: Boolean = false + + fun validate(): Scores = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 Scores && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Scores{additionalProperties=$additionalProperties}" } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SummarizeExperimentResponse && + experimentName == other.experimentName && + experimentUrl == other.experimentUrl && + projectName == other.projectName && + projectUrl == other.projectUrl && + comparisonExperimentName == other.comparisonExperimentName && + metrics == other.metrics && + scores == other.scores && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + experimentName, + experimentUrl, + projectName, + projectUrl, + comparisonExperimentName, + metrics, + scores, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SummarizeExperimentResponse{experimentName=$experimentName, experimentUrl=$experimentUrl, projectName=$projectName, projectUrl=$projectUrl, comparisonExperimentName=$comparisonExperimentName, metrics=$metrics, scores=$scores, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Task.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Task.kt deleted file mode 100644 index e8af4b27..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/Task.kt +++ /dev/null @@ -1,156 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.databind.annotation.JsonDeserialize -import java.util.Objects - -@JsonDeserialize(builder = Task.Builder::class) -@NoAutoDetect -class Task -private constructor( - private val type: JsonField, - private val additionalProperties: Map, -) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun type(): Type = type.getRequired("type") - - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Task = apply { - if (!validated) { - type() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Task && - this.type == other.type && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(type, additionalProperties) - } - return hashCode - } - - override fun toString() = "Task{type=$type, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(task: Task) = apply { - this.type = task.type - additionalProperties(task.additionalProperties) - } - - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Task = Task(type, additionalProperties.toUnmodifiable()) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val TASK = Type(JsonField.of("task")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - TASK, - } - - enum class Value { - TASK, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - TASK -> Value.TASK - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - TASK -> Known.TASK - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ToolChoice.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ToolChoice.kt deleted file mode 100644 index b744aa7f..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ToolChoice.kt +++ /dev/null @@ -1,434 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -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.Objects - -@JsonDeserialize(using = ToolChoice.Deserializer::class) -@JsonSerialize(using = ToolChoice.Serializer::class) -class ToolChoice -private constructor( - private val auto: Auto? = null, - private val none: None? = null, - private val function: Function? = null, - private val _json: JsonValue? = null, -) { - - private var validated: Boolean = false - - fun auto(): Auto? = auto - - fun none(): None? = none - - fun function(): Function? = function - - fun isAuto(): Boolean = auto != null - - fun isNone(): Boolean = none != null - - fun isFunction(): Boolean = function != null - - fun asAuto(): Auto = auto.getOrThrow("auto") - - fun asNone(): None = none.getOrThrow("none") - - fun asFunction(): Function = function.getOrThrow("function") - - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { - auto != null -> visitor.visitAuto(auto) - none != null -> visitor.visitNone(none) - function != null -> visitor.visitFunction(function) - else -> visitor.unknown(_json) - } - } - - fun validate(): ToolChoice = apply { - if (!validated) { - if (auto == null && none == null && function == null) { - throw BraintrustInvalidDataException("Unknown ToolChoice: $_json") - } - function?.validate() - validated = true - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ToolChoice && - this.auto == other.auto && - this.none == other.none && - this.function == other.function - } - - override fun hashCode(): Int { - return Objects.hash( - auto, - none, - function, - ) - } - - override fun toString(): String { - return when { - auto != null -> "ToolChoice{auto=$auto}" - none != null -> "ToolChoice{none=$none}" - function != null -> "ToolChoice{function=$function}" - _json != null -> "ToolChoice{_unknown=$_json}" - else -> throw IllegalStateException("Invalid ToolChoice") - } - } - - companion object { - - fun ofAuto(auto: Auto) = ToolChoice(auto = auto) - - fun ofNone(none: None) = ToolChoice(none = none) - - fun ofFunction(function: Function) = ToolChoice(function = function) - } - - interface Visitor { - - fun visitAuto(auto: Auto): T - - fun visitNone(none: None): T - - fun visitFunction(function: Function): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown ToolChoice: $json") - } - } - - class Deserializer : BaseDeserializer(ToolChoice::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): ToolChoice { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return ToolChoice(auto = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef())?.let { - return ToolChoice(none = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef()) { it.validate() } - ?.let { - return ToolChoice(function = it, _json = json) - } - - return ToolChoice(_json = json) - } - } - - class Serializer : BaseSerializer(ToolChoice::class) { - - override fun serialize( - value: ToolChoice, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.none != null -> generator.writeObject(value.none) - value.function != null -> generator.writeObject(value.function) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid ToolChoice") - } - } - } - - class Auto - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Auto && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val AUTO = Auto(JsonField.of("auto")) - - fun of(value: String) = Auto(JsonField.of(value)) - } - - enum class Known { - AUTO, - } - - enum class Value { - AUTO, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - AUTO -> Value.AUTO - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - AUTO -> Known.AUTO - else -> throw BraintrustInvalidDataException("Unknown Auto: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - - class None - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is None && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val NONE = None(JsonField.of("none")) - - fun of(value: String) = None(JsonField.of(value)) - } - - enum class Known { - NONE, - } - - enum class Value { - NONE, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - NONE -> Value.NONE - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - NONE -> Known.NONE - else -> throw BraintrustInvalidDataException("Unknown None: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - - @JsonDeserialize(builder = Function.Builder::class) - @NoAutoDetect - class Function - private constructor( - private val type: JsonField, - private val function: JsonField, - private val additionalProperties: Map, - ) { - - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun type(): Type = type.getRequired("type") - - fun function(): FunctionToolChoice = function.getRequired("function") - - @JsonProperty("type") @ExcludeMissing fun _type() = type - - @JsonProperty("function") @ExcludeMissing fun _function() = function - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): Function = apply { - if (!validated) { - type() - function().validate() - validated = true - } - } - - fun toBuilder() = Builder().from(this) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Function && - this.type == other.type && - this.function == other.function && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - type, - function, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "Function{type=$type, function=$function, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() - } - - class Builder { - - private var type: JsonField = JsonMissing.of() - private var function: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(function: Function) = apply { - this.type = function.type - this.function = function.function - additionalProperties(function.additionalProperties) - } - - fun type(type: Type) = type(JsonField.of(type)) - - @JsonProperty("type") - @ExcludeMissing - fun type(type: JsonField) = apply { this.type = type } - - fun function(function: FunctionToolChoice) = function(JsonField.of(function)) - - @JsonProperty("function") - @ExcludeMissing - fun function(function: JsonField) = apply { - this.function = function - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): Function = - Function( - type, - function, - additionalProperties.toUnmodifiable(), - ) - } - - class Type - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val FUNCTION = Type(JsonField.of("function")) - - fun of(value: String) = Type(JsonField.of(value)) - } - - enum class Known { - FUNCTION, - } - - enum class Value { - FUNCTION, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - FUNCTION -> Value.FUNCTION - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - FUNCTION -> Known.FUNCTION - else -> throw BraintrustInvalidDataException("Unknown Type: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParams.kt index 152c611c..0ca4afea 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParams.kt @@ -2,104 +2,168 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Default endpoint. Simply replies with 'Hello, World!'. Authorization is not required */ class TopLevelHelloWorldParams -constructor( - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun _additionalQueryParams(): Map> = additionalQueryParams + fun toBuilder() = Builder().from(this) - fun _additionalHeaders(): Map> = additionalHeaders + companion object { - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun none(): TopLevelHelloWorldParams = builder().build() - return other is TopLevelHelloWorldParams && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders + /** Returns a mutable builder for constructing an instance of [TopLevelHelloWorldParams]. */ + fun builder() = Builder() } - override fun hashCode(): Int { - return Objects.hash(additionalQueryParams, additionalHeaders) - } + /** A builder for [TopLevelHelloWorldParams]. */ + class Builder internal constructor() { - override fun toString() = - "TopLevelHelloWorldParams{additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - fun toBuilder() = Builder().from(this) + internal fun from(topLevelHelloWorldParams: TopLevelHelloWorldParams) = apply { + additionalHeaders = topLevelHelloWorldParams.additionalHeaders.toBuilder() + additionalQueryParams = topLevelHelloWorldParams.additionalQueryParams.toBuilder() + } - companion object { + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - internal fun from(topLevelHelloWorldParams: TopLevelHelloWorldParams) = apply { - additionalQueryParams(topLevelHelloWorldParams.additionalQueryParams) - additionalHeaders(topLevelHelloWorldParams.additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + 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 putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + 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 removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [TopLevelHelloWorldParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): TopLevelHelloWorldParams = - TopLevelHelloWorldParams( - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable() - ) + TopLevelHelloWorldParams(additionalHeaders.build(), additionalQueryParams.build()) + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is TopLevelHelloWorldParams && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = Objects.hash(additionalHeaders, additionalQueryParams) + + override fun toString() = + "TopLevelHelloWorldParams{additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/User.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/User.kt index 914d2158..5b92c4f2 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/User.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/User.kt @@ -6,214 +6,349 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = User.Builder::class) -@NoAutoDetect class User +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val givenName: JsonField, - private val familyName: JsonField, - private val email: JsonField, private val avatarUrl: JsonField, private val created: JsonField, - private val additionalProperties: Map, + private val email: JsonField, + private val familyName: JsonField, + private val givenName: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the user */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("avatar_url") @ExcludeMissing avatarUrl: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("email") @ExcludeMissing email: JsonField = JsonMissing.of(), + @JsonProperty("family_name") + @ExcludeMissing + familyName: JsonField = JsonMissing.of(), + @JsonProperty("given_name") @ExcludeMissing givenName: JsonField = JsonMissing.of(), + ) : this(id, avatarUrl, created, email, familyName, givenName, mutableMapOf()) + + /** + * Unique identifier for the user + * + * @throws BraintrustInvalidDataException 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") - /** Given name of the user */ - fun givenName(): String? = givenName.getNullable("given_name") - - /** Family name of the user */ - fun familyName(): String? = familyName.getNullable("family_name") - - /** The user's email */ - fun email(): String? = email.getNullable("email") - - /** URL of the user's Avatar image */ + /** + * URL of the user's Avatar image + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun avatarUrl(): String? = avatarUrl.getNullable("avatar_url") - /** Date of user creation */ + /** + * Date of user creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** Unique identifier for the user */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** Given name of the user */ - @JsonProperty("given_name") @ExcludeMissing fun _givenName() = givenName - - /** Family name of the user */ - @JsonProperty("family_name") @ExcludeMissing fun _familyName() = familyName + /** + * The user's email + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun email(): String? = email.getNullable("email") - /** The user's email */ - @JsonProperty("email") @ExcludeMissing fun _email() = email + /** + * Family name of the user + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun familyName(): String? = familyName.getNullable("family_name") - /** URL of the user's Avatar image */ - @JsonProperty("avatar_url") @ExcludeMissing fun _avatarUrl() = avatarUrl + /** + * Given name of the user + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun givenName(): String? = givenName.getNullable("given_name") - /** Date of user creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created + /** + * 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 [avatarUrl]. + * + * Unlike [avatarUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("avatar_url") @ExcludeMissing fun _avatarUrl(): JsonField = avatarUrl + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [email]. + * + * Unlike [email], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("email") @ExcludeMissing fun _email(): JsonField = email + + /** + * Returns the raw JSON value of [familyName]. + * + * Unlike [familyName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("family_name") @ExcludeMissing fun _familyName(): JsonField = familyName + + /** + * Returns the raw JSON value of [givenName]. + * + * Unlike [givenName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("given_name") @ExcludeMissing fun _givenName(): JsonField = givenName + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): User = apply { - if (!validated) { - id() - givenName() - familyName() - email() - avatarUrl() - created() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is User && - this.id == other.id && - this.givenName == other.givenName && - this.familyName == other.familyName && - this.email == other.email && - this.avatarUrl == other.avatarUrl && - this.created == other.created && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - givenName, - familyName, - email, - avatarUrl, - created, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "User{id=$id, givenName=$givenName, familyName=$familyName, email=$email, avatarUrl=$avatarUrl, created=$created, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [User]. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [User]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var givenName: JsonField = JsonMissing.of() - private var familyName: JsonField = JsonMissing.of() - private var email: JsonField = JsonMissing.of() + private var id: JsonField? = null private var avatarUrl: JsonField = JsonMissing.of() private var created: JsonField = JsonMissing.of() + private var email: JsonField = JsonMissing.of() + private var familyName: JsonField = JsonMissing.of() + private var givenName: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(user: User) = apply { - this.id = user.id - this.givenName = user.givenName - this.familyName = user.familyName - this.email = user.email - this.avatarUrl = user.avatarUrl - this.created = user.created - additionalProperties(user.additionalProperties) + id = user.id + avatarUrl = user.avatarUrl + created = user.created + email = user.email + familyName = user.familyName + givenName = user.givenName + additionalProperties = user.additionalProperties.toMutableMap() } /** Unique identifier for the user */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the user */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = id } - - /** Given name of the user */ - fun givenName(givenName: String) = givenName(JsonField.of(givenName)) - - /** Given name of the user */ - @JsonProperty("given_name") - @ExcludeMissing - fun givenName(givenName: JsonField) = apply { this.givenName = givenName } + /** + * 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 } - /** Family name of the user */ - fun familyName(familyName: String) = familyName(JsonField.of(familyName)) - - /** Family name of the user */ - @JsonProperty("family_name") - @ExcludeMissing - fun familyName(familyName: JsonField) = apply { this.familyName = familyName } + /** URL of the user's Avatar image */ + fun avatarUrl(avatarUrl: String?) = avatarUrl(JsonField.ofNullable(avatarUrl)) + + /** + * Sets [Builder.avatarUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.avatarUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun avatarUrl(avatarUrl: JsonField) = apply { this.avatarUrl = avatarUrl } - /** The user's email */ - fun email(email: String) = email(JsonField.of(email)) + /** Date of user creation */ + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun created(created: JsonField) = apply { this.created = created } /** The user's email */ - @JsonProperty("email") - @ExcludeMissing + fun email(email: String?) = email(JsonField.ofNullable(email)) + + /** + * Sets [Builder.email] to an arbitrary JSON value. + * + * You should usually call [Builder.email] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun email(email: JsonField) = apply { this.email = email } - /** URL of the user's Avatar image */ - fun avatarUrl(avatarUrl: String) = avatarUrl(JsonField.of(avatarUrl)) - - /** URL of the user's Avatar image */ - @JsonProperty("avatar_url") - @ExcludeMissing - fun avatarUrl(avatarUrl: JsonField) = apply { this.avatarUrl = avatarUrl } - - /** Date of user creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) + /** Family name of the user */ + fun familyName(familyName: String?) = familyName(JsonField.ofNullable(familyName)) + + /** + * Sets [Builder.familyName] to an arbitrary JSON value. + * + * You should usually call [Builder.familyName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun familyName(familyName: JsonField) = apply { this.familyName = familyName } - /** Date of user creation */ - @JsonProperty("created") - @ExcludeMissing - fun created(created: JsonField) = apply { this.created = created } + /** Given name of the user */ + fun givenName(givenName: String?) = givenName(JsonField.ofNullable(givenName)) + + /** + * Sets [Builder.givenName] to an arbitrary JSON value. + * + * You should usually call [Builder.givenName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun givenName(givenName: JsonField) = apply { this.givenName = givenName } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [User]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): User = User( - id, - givenName, - familyName, - email, + checkRequired("id", id), avatarUrl, created, - additionalProperties.toUnmodifiable(), + email, + familyName, + givenName, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): User = apply { + if (validated) { + return@apply + } + + id() + avatarUrl() + created() + email() + familyName() + givenName() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (avatarUrl.asKnown() == null) 0 else 1) + + (if (created.asKnown() == null) 0 else 1) + + (if (email.asKnown() == null) 0 else 1) + + (if (familyName.asKnown() == null) 0 else 1) + + (if (givenName.asKnown() == null) 0 else 1) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is User && + id == other.id && + avatarUrl == other.avatarUrl && + created == other.created && + email == other.email && + familyName == other.familyName && + givenName == other.givenName && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, avatarUrl, created, email, familyName, givenName, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "User{id=$id, avatarUrl=$avatarUrl, created=$created, email=$email, familyName=$familyName, givenName=$givenName, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPage.kt index 1de76f83..311a5064 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPage.kt @@ -2,172 +2,120 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.UserService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see UserService.list */ class UserListPage private constructor( - private val usersService: UserService, + private val service: UserService, private val params: UserListParams, - private val response: Response, -) { + private val response: UserListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [UserListPageResponse], but gracefully handles missing data. + * + * @see UserListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is UserListPage && - this.usersService == other.usersService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - usersService, - params, - response, - ) - } - - override fun toString() = - "UserListPage{usersService=$usersService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPageParams(): UserListParams? { - if (!hasNextPage()) { - return null - } - - return if (params.endingBefore() != null) { - UserListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): UserListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - UserListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): UserListPage? { - return getNextPageParams()?.let { usersService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(usersService: UserService, params: UserListParams, response: Response) = - UserListPage( - usersService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): UserListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): UserListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): UserListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [UserListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [UserListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: UserService? = null + private var params: UserListParams? = null + private var response: UserListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(userListPage: UserListPage) = apply { + service = userListPage.service + params = userListPage.params + response = userListPage.response } - override fun toString() = - "UserListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: UserService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: UserListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: UserListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [UserListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UserListPage = + UserListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is UserListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: UserListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = "UserListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPageAsync.kt index c2eaeaf2..c69929fc 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPageAsync.kt @@ -2,174 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.UserServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see UserServiceAsync.list */ class UserListPageAsync private constructor( - private val usersService: UserServiceAsync, + private val service: UserServiceAsync, private val params: UserListParams, - private val response: Response, -) { + private val response: UserListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [UserListPageResponse], but gracefully handles missing data. + * + * @see UserListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is UserListPageAsync && - this.usersService == other.usersService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - usersService, - params, - response, - ) - } - - override fun toString() = - "UserListPageAsync{usersService=$usersService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): UserListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - UserListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): UserListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - UserListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): UserListPageAsync? { - return getNextPageParams()?.let { usersService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(usersService: UserServiceAsync, params: UserListParams, response: Response) = - UserListPageAsync( - usersService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): UserListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): UserListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): UserListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [UserListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [UserListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: UserServiceAsync? = null + private var params: UserListParams? = null + private var response: UserListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(userListPageAsync: UserListPageAsync) = apply { + service = userListPageAsync.service + params = userListPageAsync.params + response = userListPageAsync.response } - override fun toString() = - "UserListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: UserServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: UserListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: UserListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [UserListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UserListPageAsync = + UserListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is UserListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: UserListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "UserListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPageResponse.kt new file mode 100644 index 00000000..f08d3b6b --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListPageResponse.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 UserListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of user objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [UserListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [UserListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(userListPageResponse: UserListPageResponse) = apply { + objects = userListPageResponse.objects.map { it.toMutableList() } + additionalProperties = userListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of user objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [User] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: User) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [UserListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UserListPageResponse = + UserListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): UserListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is UserListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "UserListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListParams.kt index 2897e6ed..61ef834e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserListParams.kt @@ -2,25 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all users. The users are sorted by creation date, with the most recently-created users + * coming first + */ class UserListParams -constructor( +private constructor( private val email: Email?, private val endingBefore: String?, private val familyName: FamilyName?, @@ -29,91 +23,76 @@ constructor( private val limit: Long?, private val orgName: String?, private val startingAfter: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { - + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Email of the user to search for. You may pass the param multiple times to filter for more + * than one email + */ fun email(): Email? = email + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Family name of the user to search for. You may pass the param multiple times to filter for + * more than one family name + */ fun familyName(): FamilyName? = familyName + /** + * Given name of the user to search for. You may pass the param multiple times to filter for + * more than one given name + */ fun givenName(): GivenName? = givenName + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** Filter search results to within a particular organization */ fun orgName(): String? = orgName + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.email?.let { params.put("email", listOf(it.toString())) } - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.familyName?.let { params.put("family_name", listOf(it.toString())) } - this.givenName?.let { params.put("given_name", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.orgName?.let { params.put("org_name", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is UserListParams && - this.email == other.email && - this.endingBefore == other.endingBefore && - this.familyName == other.familyName && - this.givenName == other.givenName && - this.ids == other.ids && - this.limit == other.limit && - this.orgName == other.orgName && - this.startingAfter == other.startingAfter && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - email, - endingBefore, - familyName, - givenName, - ids, - limit, - orgName, - startingAfter, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "UserListParams{email=$email, endingBefore=$endingBefore, familyName=$familyName, givenName=$givenName, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun toBuilder() = Builder().from(this) companion object { + fun none(): UserListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [UserListParams]. */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [UserListParams]. */ + class Builder internal constructor() { private var email: Email? = null private var endingBefore: String? = null @@ -123,39 +102,33 @@ constructor( private var limit: Long? = null private var orgName: String? = null private var startingAfter: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(userListParams: UserListParams) = apply { - this.email = userListParams.email - this.endingBefore = userListParams.endingBefore - this.familyName = userListParams.familyName - this.givenName = userListParams.givenName - this.ids = userListParams.ids - this.limit = userListParams.limit - this.orgName = userListParams.orgName - this.startingAfter = userListParams.startingAfter - additionalQueryParams(userListParams.additionalQueryParams) - additionalHeaders(userListParams.additionalHeaders) + email = userListParams.email + endingBefore = userListParams.endingBefore + familyName = userListParams.familyName + givenName = userListParams.givenName + ids = userListParams.ids + limit = userListParams.limit + orgName = userListParams.orgName + startingAfter = userListParams.startingAfter + additionalHeaders = userListParams.additionalHeaders.toBuilder() + additionalQueryParams = userListParams.additionalQueryParams.toBuilder() } /** * Email of the user to search for. You may pass the param multiple times to filter for more * than one email */ - fun email(email: Email) = apply { this.email = email } + fun email(email: Email?) = apply { this.email = email } - /** - * Email of the user to search for. You may pass the param multiple times to filter for more - * than one email - */ - fun email(string: String) = apply { this.email = Email.ofString(string) } + /** Alias for calling [email] with `Email.ofString(string)`. */ + fun email(string: String) = email(Email.ofString(string)) - /** - * Email of the user to search for. You may pass the param multiple times to filter for more - * than one email - */ - fun email(strings: List) = apply { this.email = Email.ofStrings(strings) } + /** Alias for calling [email] with `Email.ofStrings(strings)`. */ + fun emailOfStrings(strings: List) = email(Email.ofStrings(strings)) /** * Pagination cursor id. @@ -164,71 +137,56 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Family name of the user to search for. You may pass the param multiple times to filter * for more than one family name */ - fun familyName(familyName: FamilyName) = apply { this.familyName = familyName } + fun familyName(familyName: FamilyName?) = apply { this.familyName = familyName } - /** - * Family name of the user to search for. You may pass the param multiple times to filter - * for more than one family name - */ - fun familyName(string: String) = apply { this.familyName = FamilyName.ofString(string) } + /** Alias for calling [familyName] with `FamilyName.ofString(string)`. */ + fun familyName(string: String) = familyName(FamilyName.ofString(string)) - /** - * Family name of the user to search for. You may pass the param multiple times to filter - * for more than one family name - */ - fun familyName(strings: List) = apply { - this.familyName = FamilyName.ofStrings(strings) - } + /** Alias for calling [familyName] with `FamilyName.ofStrings(strings)`. */ + fun familyNameOfStrings(strings: List) = familyName(FamilyName.ofStrings(strings)) /** * Given name of the user to search for. You may pass the param multiple times to filter for * more than one given name */ - fun givenName(givenName: GivenName) = apply { this.givenName = givenName } + fun givenName(givenName: GivenName?) = apply { this.givenName = givenName } - /** - * Given name of the user to search for. You may pass the param multiple times to filter for - * more than one given name - */ - fun givenName(string: String) = apply { this.givenName = GivenName.ofString(string) } + /** Alias for calling [givenName] with `GivenName.ofString(string)`. */ + fun givenName(string: String) = givenName(GivenName.ofString(string)) - /** - * Given name of the user to search for. You may pass the param multiple times to filter for - * more than one given name - */ - fun givenName(strings: List) = apply { - this.givenName = GivenName.ofStrings(strings) - } + /** Alias for calling [givenName] with `GivenName.ofStrings(strings)`. */ + fun givenNameOfStrings(strings: List) = givenName(GivenName.ofStrings(strings)) /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** Filter search results to within a particular organization */ - fun orgName(orgName: String) = apply { this.orgName = orgName } + fun orgName(orgName: String?) = apply { this.orgName = orgName } /** * Pagination cursor id. @@ -237,48 +195,111 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [UserListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): UserListParams = UserListParams( email, @@ -289,22 +310,78 @@ constructor( limit, orgName, startingAfter, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - @JsonDeserialize(using = Email.Deserializer::class) - @JsonSerialize(using = Email.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + email?.accept( + object : Email.Visitor { + override fun visitString(string: String) { + put("email", string) + } + + override fun visitStrings(strings: List) { + put("email", strings.joinToString(",")) + } + } + ) + endingBefore?.let { put("ending_before", it) } + familyName?.accept( + object : FamilyName.Visitor { + override fun visitString(string: String) { + put("family_name", string) + } + + override fun visitStrings(strings: List) { + put("family_name", strings.joinToString(",")) + } + } + ) + givenName?.accept( + object : GivenName.Visitor { + override fun visitString(string: String) { + put("given_name", string) + } + + override fun visitStrings(strings: List) { + put("given_name", strings.joinToString(",")) + } + } + ) + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + orgName?.let { put("org_name", it) } + startingAfter?.let { put("starting_after", it) } + putAll(additionalQueryParams) + } + .build() + + /** + * Email of the user to search for. You may pass the param multiple times to filter for more + * than one email + */ class Email private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -317,107 +394,56 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Email = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Email: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Email") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Email && this.string == other.string && this.strings == other.strings + return other is Email && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Email{string=$string}" strings != null -> "Email{strings=$strings}" - _json != null -> "Email{_unknown=$_json}" else -> throw IllegalStateException("Invalid Email") } - } companion object { fun ofString(string: String) = Email(string = string) - fun ofStrings(strings: List) = Email(strings = strings) + fun ofStrings(strings: List) = Email(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Email] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Email: $json") - } - } - - class Deserializer : BaseDeserializer(Email::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Email { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Email(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Email(strings = it, _json = json) - } - - return Email(_json = json) - } - } - - class Serializer : BaseSerializer(Email::class) { - - override fun serialize( - value: Email, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Email") - } - } } } - @JsonDeserialize(using = FamilyName.Deserializer::class) - @JsonSerialize(using = FamilyName.Serializer::class) + /** + * Family name of the user to search for. You may pass the param multiple times to filter for + * more than one family name + */ class FamilyName private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -430,109 +456,58 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): FamilyName = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown FamilyName: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid FamilyName") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is FamilyName && - this.string == other.string && - this.strings == other.strings + return other is FamilyName && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "FamilyName{string=$string}" strings != null -> "FamilyName{strings=$strings}" - _json != null -> "FamilyName{_unknown=$_json}" else -> throw IllegalStateException("Invalid FamilyName") } - } companion object { fun ofString(string: String) = FamilyName(string = string) - fun ofStrings(strings: List) = FamilyName(strings = strings) + fun ofStrings(strings: List) = FamilyName(strings = strings.toImmutable()) } + /** + * An interface that defines how to map each variant of [FamilyName] to a value of type [T]. + */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown FamilyName: $json") - } - } - - class Deserializer : BaseDeserializer(FamilyName::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): FamilyName { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return FamilyName(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return FamilyName(strings = it, _json = json) - } - - return FamilyName(_json = json) - } - } - - class Serializer : BaseSerializer(FamilyName::class) { - - override fun serialize( - value: FamilyName, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid FamilyName") - } - } } } - @JsonDeserialize(using = GivenName.Deserializer::class) - @JsonSerialize(using = GivenName.Serializer::class) + /** + * Given name of the user to search for. You may pass the param multiple times to filter for + * more than one given name + */ class GivenName private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -545,109 +520,58 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): GivenName = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown GivenName: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid GivenName") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is GivenName && - this.string == other.string && - this.strings == other.strings + return other is GivenName && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "GivenName{string=$string}" strings != null -> "GivenName{strings=$strings}" - _json != null -> "GivenName{_unknown=$_json}" else -> throw IllegalStateException("Invalid GivenName") } - } companion object { fun ofString(string: String) = GivenName(string = string) - fun ofStrings(strings: List) = GivenName(strings = strings) + fun ofStrings(strings: List) = GivenName(strings = strings.toImmutable()) } + /** + * An interface that defines how to map each variant of [GivenName] to a value of type [T]. + */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown GivenName: $json") - } - } - - class Deserializer : BaseDeserializer(GivenName::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): GivenName { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return GivenName(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return GivenName(strings = it, _json = json) - } - - return GivenName(_json = json) - } - } - - class Serializer : BaseSerializer(GivenName::class) { - - override fun serialize( - value: GivenName, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid GivenName") - } - } } } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -660,93 +584,78 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } } + } - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } - } + return other is UserListParams && + email == other.email && + endingBefore == other.endingBefore && + familyName == other.familyName && + givenName == other.givenName && + ids == other.ids && + limit == other.limit && + orgName == other.orgName && + startingAfter == other.startingAfter && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash( + email, + endingBefore, + familyName, + givenName, + ids, + limit, + orgName, + startingAfter, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "UserListParams{email=$email, endingBefore=$endingBefore, familyName=$familyName, givenName=$givenName, ids=$ids, limit=$limit, orgName=$orgName, startingAfter=$startingAfter, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserRetrieveParams.kt index c2078548..ec9bde4f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/UserRetrieveParams.kt @@ -2,125 +2,184 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a user object by its id */ class UserRetrieveParams -constructor( - private val userId: String, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { +private constructor( + private val userId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun userId(): String = userId + /** User id */ + fun userId(): String? = userId - internal fun getQueryParams(): Map> = additionalQueryParams + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams - fun getPathParam(index: Int): String { - return when (index) { - 0 -> userId - else -> "" - } + fun toBuilder() = Builder().from(this) + + companion object { + + fun none(): UserRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [UserRetrieveParams]. */ + fun builder() = Builder() } - fun _additionalQueryParams(): Map> = additionalQueryParams + /** A builder for [UserRetrieveParams]. */ + class Builder internal constructor() { - fun _additionalHeaders(): Map> = additionalHeaders + private var userId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + internal fun from(userRetrieveParams: UserRetrieveParams) = apply { + userId = userRetrieveParams.userId + additionalHeaders = userRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = userRetrieveParams.additionalQueryParams.toBuilder() } - return other is UserRetrieveParams && - this.userId == other.userId && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } + /** User id */ + fun userId(userId: String?) = apply { this.userId = userId } - override fun hashCode(): Int { - return Objects.hash( - userId, - additionalQueryParams, - additionalHeaders, - ) - } + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "UserRetrieveParams{userId=$userId, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders}" + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - companion object { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - private var userId: String? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - internal fun from(userRetrieveParams: UserRetrieveParams) = apply { - this.userId = userRetrieveParams.userId - additionalQueryParams(userRetrieveParams.additionalQueryParams) - additionalHeaders(userRetrieveParams.additionalHeaders) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - /** User id */ - fun userId(userId: String) = apply { this.userId = userId } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + 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 putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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 [UserRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): UserRetrieveParams = - UserRetrieveParams( - checkNotNull(userId) { "`userId` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) + UserRetrieveParams(userId, additionalHeaders.build(), additionalQueryParams.build()) } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> userId ?: "" + 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 UserRetrieveParams && + userId == other.userId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(userId, additionalHeaders, additionalQueryParams) + + override fun toString() = + "UserRetrieveParams{userId=$userId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/View.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/View.kt index f03ee759..8a014a7c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/View.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/View.kt @@ -7,504 +7,707 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = View.Builder::class) -@NoAutoDetect class View +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, - private val objectType: JsonField, + private val name: JsonField, private val objectId: JsonField, + private val objectType: JsonField, private val viewType: JsonField, - private val name: JsonField, private val created: JsonField, - private val viewData: JsonField, + private val deletedAt: JsonField, private val options: JsonField, private val userId: JsonField, - private val deletedAt: JsonField, - private val additionalProperties: Map, + private val viewData: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - /** Unique identifier for the view */ + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("object_id") @ExcludeMissing objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("view_type") @ExcludeMissing viewType: JsonField = JsonMissing.of(), + @JsonProperty("created") + @ExcludeMissing + created: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + @JsonProperty("view_data") @ExcludeMissing viewData: JsonField = JsonMissing.of(), + ) : this( + id, + name, + objectId, + objectType, + viewType, + created, + deletedAt, + options, + userId, + viewData, + mutableMapOf(), + ) + + /** + * Unique identifier for the view + * + * @throws BraintrustInvalidDataException 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") - /** The object type that the ACL applies to */ - fun objectType(): ObjectType = objectType.getRequired("object_type") + /** + * Name of the view + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") - /** The id of the object the view applies to */ + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") - /** Type of table that the view corresponds to. */ + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") + + /** + * Type of table that the view corresponds to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun viewType(): ViewType? = viewType.getNullable("view_type") - /** Name of the view */ - fun name(): String = name.getRequired("name") - - /** Date of view creation */ + /** + * Date of view creation + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun created(): OffsetDateTime? = created.getNullable("created") - /** The view definition */ - fun viewData(): ViewData? = viewData.getNullable("view_data") + /** + * Date of role deletion, or null if the role is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - /** Options for the view in the app */ + /** + * Options for the view in the app + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun options(): ViewOptions? = options.getNullable("options") - /** Identifies the user who created the view */ + /** + * Identifies the user who created the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun userId(): String? = userId.getNullable("user_id") - /** Date of role deletion, or null if the role is still active */ - fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") - - /** Unique identifier for the view */ - @JsonProperty("id") @ExcludeMissing fun _id() = id - - /** The object type that the ACL applies to */ - @JsonProperty("object_type") @ExcludeMissing fun _objectType() = objectType - - /** The id of the object the view applies to */ - @JsonProperty("object_id") @ExcludeMissing fun _objectId() = objectId - - /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") @ExcludeMissing fun _viewType() = viewType - - /** Name of the view */ - @JsonProperty("name") @ExcludeMissing fun _name() = name - - /** Date of view creation */ - @JsonProperty("created") @ExcludeMissing fun _created() = created - - /** The view definition */ - @JsonProperty("view_data") @ExcludeMissing fun _viewData() = viewData - - /** Options for the view in the app */ - @JsonProperty("options") @ExcludeMissing fun _options() = options - - /** Identifies the user who created the view */ - @JsonProperty("user_id") @ExcludeMissing fun _userId() = userId + /** + * The view definition + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun viewData(): ViewData? = viewData.getNullable("view_data") - /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") @ExcludeMissing fun _deletedAt() = deletedAt + /** + * 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 [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [viewType]. + * + * Unlike [viewType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_type") @ExcludeMissing fun _viewType(): JsonField = viewType + + /** + * Returns the raw JSON value of [created]. + * + * Unlike [created], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created") @ExcludeMissing fun _created(): JsonField = created + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + /** + * Returns the raw JSON value of [viewData]. + * + * Unlike [viewData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_data") @ExcludeMissing fun _viewData(): JsonField = viewData + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): View = apply { - if (!validated) { - id() - objectType() - objectId() - viewType() - name() - created() - viewData()?.validate() - options()?.validate() - userId() - deletedAt() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is View && - this.id == other.id && - this.objectType == other.objectType && - this.objectId == other.objectId && - this.viewType == other.viewType && - this.name == other.name && - this.created == other.created && - this.viewData == other.viewData && - this.options == other.options && - this.userId == other.userId && - this.deletedAt == other.deletedAt && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - id, - objectType, - objectId, - viewType, - name, - created, - viewData, - options, - userId, - deletedAt, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "View{id=$id, objectType=$objectType, objectId=$objectId, viewType=$viewType, name=$name, created=$created, viewData=$viewData, options=$options, userId=$userId, deletedAt=$deletedAt, additionalProperties=$additionalProperties}" - companion object { + /** + * Returns a mutable builder for constructing an instance of [View]. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + */ fun builder() = Builder() } - class Builder { + /** A builder for [View]. */ + class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() - private var objectType: JsonField = JsonMissing.of() - private var objectId: JsonField = JsonMissing.of() - private var viewType: JsonField = JsonMissing.of() - private var name: JsonField = JsonMissing.of() + private var id: JsonField? = null + private var name: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var viewType: JsonField? = null private var created: JsonField = JsonMissing.of() - private var viewData: JsonField = JsonMissing.of() + private var deletedAt: JsonField = JsonMissing.of() private var options: JsonField = JsonMissing.of() private var userId: JsonField = JsonMissing.of() - private var deletedAt: JsonField = JsonMissing.of() + private var viewData: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(view: View) = apply { - this.id = view.id - this.objectType = view.objectType - this.objectId = view.objectId - this.viewType = view.viewType - this.name = view.name - this.created = view.created - this.viewData = view.viewData - this.options = view.options - this.userId = view.userId - this.deletedAt = view.deletedAt - additionalProperties(view.additionalProperties) + id = view.id + name = view.name + objectId = view.objectId + objectType = view.objectType + viewType = view.viewType + created = view.created + deletedAt = view.deletedAt + options = view.options + userId = view.userId + viewData = view.viewData + additionalProperties = view.additionalProperties.toMutableMap() } /** Unique identifier for the view */ fun id(id: String) = id(JsonField.of(id)) - /** Unique identifier for the view */ - @JsonProperty("id") @ExcludeMissing fun id(id: JsonField) = apply { this.id = 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 } - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = objectType(JsonField.of(objectType)) + /** Name of the view */ + fun name(name: String) = name(JsonField.of(name)) - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - @ExcludeMissing - fun objectType(objectType: JsonField) = apply { this.objectType = objectType } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } /** The id of the object the view applies to */ fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - /** The id of the object the view applies to */ - @JsonProperty("object_id") - @ExcludeMissing + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - /** Type of table that the view corresponds to. */ - fun viewType(viewType: ViewType) = viewType(JsonField.of(viewType)) + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") - @ExcludeMissing + fun viewType(viewType: ViewType?) = viewType(JsonField.ofNullable(viewType)) + + /** + * Sets [Builder.viewType] to an arbitrary JSON value. + * + * You should usually call [Builder.viewType] with a well-typed [ViewType] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ fun viewType(viewType: JsonField) = apply { this.viewType = viewType } - /** Name of the view */ - fun name(name: String) = name(JsonField.of(name)) - - /** Name of the view */ - @JsonProperty("name") - @ExcludeMissing - fun name(name: JsonField) = apply { this.name = name } - - /** Date of view creation */ - fun created(created: OffsetDateTime) = created(JsonField.of(created)) - /** Date of view creation */ - @JsonProperty("created") - @ExcludeMissing + fun created(created: OffsetDateTime?) = created(JsonField.ofNullable(created)) + + /** + * Sets [Builder.created] to an arbitrary JSON value. + * + * You should usually call [Builder.created] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun created(created: JsonField) = apply { this.created = created } - /** The view definition */ - fun viewData(viewData: ViewData) = viewData(JsonField.of(viewData)) - - /** The view definition */ - @JsonProperty("view_data") - @ExcludeMissing - fun viewData(viewData: JsonField) = apply { this.viewData = viewData } - - /** Options for the view in the app */ - fun options(options: ViewOptions) = options(JsonField.of(options)) + /** Date of role deletion, or null if the role is still active */ + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } /** Options for the view in the app */ - @JsonProperty("options") - @ExcludeMissing + fun options(options: ViewOptions?) = options(JsonField.ofNullable(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [ViewOptions] 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 } /** Identifies the user who created the view */ - fun userId(userId: String) = userId(JsonField.of(userId)) - - /** Identifies the user who created the view */ - @JsonProperty("user_id") - @ExcludeMissing + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ fun userId(userId: JsonField) = apply { this.userId = userId } - /** Date of role deletion, or null if the role is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = deletedAt(JsonField.of(deletedAt)) - - /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") - @ExcludeMissing - fun deletedAt(deletedAt: JsonField) = apply { this.deletedAt = deletedAt } + /** The view definition */ + fun viewData(viewData: ViewData?) = viewData(JsonField.ofNullable(viewData)) + + /** + * Sets [Builder.viewData] to an arbitrary JSON value. + * + * You should usually call [Builder.viewData] with a well-typed [ViewData] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewData(viewData: JsonField) = apply { this.viewData = viewData } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [View]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .id() + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): View = View( - id, - objectType, - objectId, - viewType, - name, + checkRequired("id", id), + checkRequired("name", name), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + checkRequired("viewType", viewType), created, - viewData, + deletedAt, options, userId, - deletedAt, - additionalProperties.toUnmodifiable(), + viewData, + additionalProperties.toMutableMap(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + private var validated: Boolean = false - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun validate(): View = apply { + if (validated) { + return@apply + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + id() + name() + objectId() + objectType().validate() + viewType()?.validate() + created() + deletedAt() + options()?.validate() + userId() + viewData()?.validate() + validated = true + } - return other is ObjectType && this.value == other.value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - override fun hashCode() = value.hashCode() + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (id.asKnown() == null) 0 else 1) + + (if (name.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (viewType.asKnown()?.validity() ?: 0) + + (if (created.asKnown() == null) 0 else 1) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (options.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + + (viewData.asKnown()?.validity() ?: 0) - override fun toString() = value.toString() + /** Type of table that the view corresponds to. */ + class ViewType @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 { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + val PROJECTS = of("projects") - val PROJECT = ObjectType(JsonField.of("project")) + val EXPERIMENTS = of("experiments") - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + val EXPERIMENT = of("experiment") - val DATASET = ObjectType(JsonField.of("dataset")) + val PLAYGROUNDS = of("playgrounds") - val PROMPT = ObjectType(JsonField.of("prompt")) + val PLAYGROUND = of("playground") - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + val DATASETS = of("datasets") - val GROUP = ObjectType(JsonField.of("group")) + val DATASET = of("dataset") - val ROLE = ObjectType(JsonField.of("role")) + val PROMPTS = of("prompts") - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + val TOOLS = of("tools") - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + val SCORERS = of("scorers") - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + val LOGS = of("logs") - fun of(value: String) = ObjectType(JsonField.of(value)) + fun of(value: String) = ViewType(JsonField.of(value)) } + /** An enum containing [ViewType]'s known values. */ enum class Known { - ORGANIZATION, - PROJECT, + PROJECTS, + EXPERIMENTS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + PROMPTS, + TOOLS, + SCORERS, + LOGS, } + /** + * An enum containing [ViewType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ViewType] 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 { - ORGANIZATION, - PROJECT, + PROJECTS, + EXPERIMENTS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + PROMPTS, + TOOLS, + SCORERS, + LOGS, + /** An enum member indicating that [ViewType] 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) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT + PROJECTS -> Value.PROJECTS + EXPERIMENTS -> Value.EXPERIMENTS EXPERIMENT -> Value.EXPERIMENT + PLAYGROUNDS -> Value.PLAYGROUNDS + PLAYGROUND -> Value.PLAYGROUND + DATASETS -> Value.DATASETS DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT + PROMPTS -> Value.PROMPTS + TOOLS -> Value.TOOLS + SCORERS -> Value.SCORERS + LOGS -> Value.LOGS 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT + PROJECTS -> Known.PROJECTS + EXPERIMENTS -> Known.EXPERIMENTS EXPERIMENT -> Known.EXPERIMENT + PLAYGROUNDS -> Known.PLAYGROUNDS + PLAYGROUND -> Known.PLAYGROUND + DATASETS -> Known.DATASETS DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") + PROMPTS -> Known.PROMPTS + TOOLS -> Known.TOOLS + SCORERS -> Known.SCORERS + LOGS -> Known.LOGS + else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") } - fun asString(): String = _value().asStringOrThrow() - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ViewType = apply { + if (validated) { + return@apply + } - class ViewType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ViewType && this.value == other.value + return other is ViewType && value == other.value } override fun hashCode() = value.hashCode() override fun toString() = value.toString() + } - companion object { - - val PROJECTS = ViewType(JsonField.of("projects")) - - val LOGS = ViewType(JsonField.of("logs")) - - val EXPERIMENTS = ViewType(JsonField.of("experiments")) - - val DATASETS = ViewType(JsonField.of("datasets")) - - val PROMPTS = ViewType(JsonField.of("prompts")) - - val PLAYGROUNDS = ViewType(JsonField.of("playgrounds")) - - val EXPERIMENT = ViewType(JsonField.of("experiment")) - - val DATASET = ViewType(JsonField.of("dataset")) - - fun of(value: String) = ViewType(JsonField.of(value)) - } - - enum class Known { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - enum class Value { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, - _UNKNOWN, - } + return other is View && + id == other.id && + name == other.name && + objectId == other.objectId && + objectType == other.objectType && + viewType == other.viewType && + created == other.created && + deletedAt == other.deletedAt && + options == other.options && + userId == other.userId && + viewData == other.viewData && + additionalProperties == other.additionalProperties + } - fun value(): Value = - when (this) { - PROJECTS -> Value.PROJECTS - LOGS -> Value.LOGS - EXPERIMENTS -> Value.EXPERIMENTS - DATASETS -> Value.DATASETS - PROMPTS -> Value.PROMPTS - PLAYGROUNDS -> Value.PLAYGROUNDS - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - else -> Value._UNKNOWN - } + private val hashCode: Int by lazy { + Objects.hash( + id, + name, + objectId, + objectType, + viewType, + created, + deletedAt, + options, + userId, + viewData, + additionalProperties, + ) + } - fun known(): Known = - when (this) { - PROJECTS -> Known.PROJECTS - LOGS -> Known.LOGS - EXPERIMENTS -> Known.EXPERIMENTS - DATASETS -> Known.DATASETS - PROMPTS -> Known.PROMPTS - PLAYGROUNDS -> Known.PLAYGROUNDS - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") - } + override fun hashCode(): Int = hashCode - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "View{id=$id, name=$name, objectId=$objectId, objectType=$objectType, viewType=$viewType, created=$created, deletedAt=$deletedAt, options=$options, userId=$userId, viewData=$viewData, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewCreateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewCreateParams.kt index 166d278d..71a5a66e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewCreateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewCreateParams.kt @@ -5,268 +5,477 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects +/** + * Create a new view. If there is an existing view with the same name as the one specified in the + * request, will return the existing view unmodified + */ class ViewCreateParams -constructor( - private val name: String, - private val objectId: String, - private val objectType: ObjectType, - private val viewType: ViewType?, - private val deletedAt: OffsetDateTime?, - private val options: ViewOptions?, - private val userId: String?, - private val viewData: ViewData?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the view + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = body.objectType() + + /** + * Type of table that the view corresponds to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun viewType(): ViewType? = body.viewType() + + /** + * Date of role deletion, or null if the role is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun deletedAt(): OffsetDateTime? = body.deletedAt() + + /** + * Options for the view in the app + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): ViewOptions? = body.options() + + /** + * Identifies the user who created the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = body.userId() + + /** + * The view definition + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun viewData(): ViewData? = body.viewData() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() + + /** + * Returns the raw JSON value of [viewType]. + * + * Unlike [viewType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _viewType(): JsonField = body._viewType() + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _deletedAt(): JsonField = body._deletedAt() + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _userId(): JsonField = body._userId() + + /** + * Returns the raw JSON value of [viewData]. + * + * Unlike [viewData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _viewData(): JsonField = body._viewData() + + 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 name(): String = name - - fun objectId(): String = objectId - - fun objectType(): ObjectType = objectType - - fun viewType(): ViewType? = viewType - - fun deletedAt(): OffsetDateTime? = deletedAt + fun toBuilder() = Builder().from(this) - fun options(): ViewOptions? = options + companion object { - fun userId(): String? = userId + /** + * Returns a mutable builder for constructing an instance of [ViewCreateParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + */ + fun builder() = Builder() + } - fun viewData(): ViewData? = viewData + /** A builder for [ViewCreateParams]. */ + class Builder internal constructor() { - internal fun getBody(): ViewCreateBody { - return ViewCreateBody( - name, - objectId, - objectType, - viewType, - deletedAt, - options, - userId, - viewData, - additionalBodyProperties, - ) - } + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = ViewCreateBody.Builder::class) - @NoAutoDetect - class ViewCreateBody - internal constructor( - private val name: String?, - private val objectId: String?, - private val objectType: ObjectType?, - private val viewType: ViewType?, - private val deletedAt: OffsetDateTime?, - private val options: ViewOptions?, - private val userId: String?, - private val viewData: ViewData?, - private val additionalProperties: Map, - ) { + internal fun from(viewCreateParams: ViewCreateParams) = apply { + body = viewCreateParams.body.toBuilder() + additionalHeaders = viewCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = viewCreateParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [objectId] + * - [objectType] + * - [viewType] + * - [deletedAt] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the view */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The id of the object the view applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + fun objectId(objectId: String) = apply { body.objectId(objectId) } + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + fun objectType(objectType: AclObjectType) = apply { body.objectType(objectType) } + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") fun viewType(): ViewType? = viewType + fun viewType(viewType: ViewType?) = apply { body.viewType(viewType) } + + /** + * Sets [Builder.viewType] to an arbitrary JSON value. + * + * You should usually call [Builder.viewType] with a well-typed [ViewType] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewType(viewType: JsonField) = apply { body.viewType(viewType) } /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") fun deletedAt(): OffsetDateTime? = deletedAt + fun deletedAt(deletedAt: OffsetDateTime?) = apply { body.deletedAt(deletedAt) } + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { body.deletedAt(deletedAt) } /** Options for the view in the app */ - @JsonProperty("options") fun options(): ViewOptions? = options + fun options(options: ViewOptions?) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [ViewOptions] 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) } /** Identifies the user who created the view */ - @JsonProperty("user_id") fun userId(): String? = userId + fun userId(userId: String?) = apply { body.userId(userId) } + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { body.userId(userId) } /** The view definition */ - @JsonProperty("view_data") fun viewData(): ViewData? = viewData + fun viewData(viewData: ViewData?) = apply { body.viewData(viewData) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.viewData] to an arbitrary JSON value. + * + * You should usually call [Builder.viewData] with a well-typed [ViewData] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewData(viewData: JsonField) = apply { body.viewData(viewData) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is ViewCreateBody && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.viewType == other.viewType && - this.deletedAt == other.deletedAt && - this.options == other.options && - this.userId == other.userId && - this.viewData == other.viewData && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - objectId, - objectType, - viewType, - deletedAt, - options, - userId, - viewData, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "ViewCreateBody{name=$name, objectId=$objectId, objectType=$objectType, viewType=$viewType, deletedAt=$deletedAt, options=$options, userId=$userId, viewData=$viewData, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var viewType: ViewType? = null - private var deletedAt: OffsetDateTime? = null - private var options: ViewOptions? = null - private var userId: String? = null - private var viewData: ViewData? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(viewCreateBody: ViewCreateBody) = apply { - this.name = viewCreateBody.name - this.objectId = viewCreateBody.objectId - this.objectType = viewCreateBody.objectType - this.viewType = viewCreateBody.viewType - this.deletedAt = viewCreateBody.deletedAt - this.options = viewCreateBody.options - this.userId = viewCreateBody.userId - this.viewData = viewCreateBody.viewData - additionalProperties(viewCreateBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the view */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** The id of the object the view applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") - fun viewType(viewType: ViewType) = apply { this.viewType = viewType } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") - fun deletedAt(deletedAt: OffsetDateTime) = apply { this.deletedAt = deletedAt } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** Options for the view in the app */ - @JsonProperty("options") - fun options(options: ViewOptions) = apply { this.options = options } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** Identifies the user who created the view */ - @JsonProperty("user_id") fun userId(userId: String) = apply { this.userId = userId } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - /** The view definition */ - @JsonProperty("view_data") - fun viewData(viewData: ViewData) = apply { this.viewData = viewData } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun build(): ViewCreateBody = - ViewCreateBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - viewType, - deletedAt, - options, - userId, - viewData, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ViewCreateParams && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.viewType == other.viewType && - this.deletedAt == other.deletedAt && - this.options == other.options && - this.userId == other.userId && - this.viewData == other.viewData && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ViewCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ViewCreateParams = + ViewCreateParams(body.build(), additionalHeaders.build(), additionalQueryParams.build()) } - override fun hashCode(): Int { - return Objects.hash( + 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 name: JsonField, + private val objectId: JsonField, + private val objectType: JsonField, + private val viewType: JsonField, + private val deletedAt: JsonField, + private val options: JsonField, + private val userId: JsonField, + private val viewData: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("view_type") + @ExcludeMissing + viewType: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("options") + @ExcludeMissing + options: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + @JsonProperty("view_data") + @ExcludeMissing + viewData: JsonField = JsonMissing.of(), + ) : this( name, objectId, objectType, @@ -275,346 +484,606 @@ constructor( options, userId, viewData, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - override fun toString() = - "ViewCreateParams{name=$name, objectId=$objectId, objectType=$objectType, viewType=$viewType, deletedAt=$deletedAt, options=$options, userId=$userId, viewData=$viewData, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) + /** + * Name of the view + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") + + /** + * Type of table that the view corresponds to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewType(): ViewType? = viewType.getNullable("view_type") + + /** + * Date of role deletion, or null if the role is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") + + /** + * Options for the view in the app + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): ViewOptions? = options.getNullable("options") + + /** + * Identifies the user who created the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") + + /** + * The view definition + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewData(): ViewData? = viewData.getNullable("view_data") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [viewType]. + * + * Unlike [viewType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_type") @ExcludeMissing fun _viewType(): JsonField = viewType + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + /** + * Returns the raw JSON value of [viewData]. + * + * Unlike [viewData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_data") @ExcludeMissing fun _viewData(): JsonField = viewData + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - companion object { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun builder() = Builder() - } + fun toBuilder() = Builder().from(this) - @NoAutoDetect - class Builder { - - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var viewType: ViewType? = null - private var deletedAt: OffsetDateTime? = null - private var options: ViewOptions? = null - private var userId: String? = null - private var viewData: ViewData? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + companion object { - internal fun from(viewCreateParams: ViewCreateParams) = apply { - this.name = viewCreateParams.name - this.objectId = viewCreateParams.objectId - this.objectType = viewCreateParams.objectType - this.viewType = viewCreateParams.viewType - this.deletedAt = viewCreateParams.deletedAt - this.options = viewCreateParams.options - this.userId = viewCreateParams.userId - this.viewData = viewCreateParams.viewData - additionalQueryParams(viewCreateParams.additionalQueryParams) - additionalHeaders(viewCreateParams.additionalHeaders) - additionalBodyProperties(viewCreateParams.additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + */ + fun builder() = Builder() } - /** Name of the view */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var viewType: JsonField? = null + private var deletedAt: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() + private var viewData: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** The id of the object the view applies to */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + internal fun from(body: Body) = apply { + name = body.name + objectId = body.objectId + objectType = body.objectType + viewType = body.viewType + deletedAt = body.deletedAt + options = body.options + userId = body.userId + viewData = body.viewData + additionalProperties = body.additionalProperties.toMutableMap() + } - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + /** Name of the view */ + fun name(name: String) = name(JsonField.of(name)) - /** Type of table that the view corresponds to. */ - fun viewType(viewType: ViewType) = apply { this.viewType = viewType } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** Date of role deletion, or null if the role is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = apply { this.deletedAt = deletedAt } + /** The id of the object the view applies to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - /** Options for the view in the app */ - fun options(options: ViewOptions) = apply { this.options = options } + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - /** Identifies the user who created the view */ - fun userId(userId: String) = apply { this.userId = userId } + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - /** The view definition */ - fun viewData(viewData: ViewData) = apply { this.viewData = viewData } + /** Type of table that the view corresponds to. */ + fun viewType(viewType: ViewType?) = viewType(JsonField.ofNullable(viewType)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.viewType] to an arbitrary JSON value. + * + * You should usually call [Builder.viewType] with a well-typed [ViewType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun viewType(viewType: JsonField) = apply { this.viewType = viewType } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Date of role deletion, or null if the role is still active */ + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { + this.deletedAt = deletedAt + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** Options for the view in the app */ + fun options(options: ViewOptions?) = options(JsonField.ofNullable(options)) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [ViewOptions] 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 removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** Identifies the user who created the view */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + /** The view definition */ + fun viewData(viewData: ViewData?) = viewData(JsonField.ofNullable(viewData)) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Sets [Builder.viewData] to an arbitrary JSON value. + * + * You should usually call [Builder.viewData] with a well-typed [ViewData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun viewData(viewData: JsonField) = apply { this.viewData = viewData } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + 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: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + checkRequired("viewType", viewType), + deletedAt, + options, + userId, + viewData, + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply } - fun build(): ViewCreateParams = - ViewCreateParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - viewType, - deletedAt, - options, - userId, - viewData, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + name() + objectId() + objectType().validate() + viewType()?.validate() + deletedAt() + options()?.validate() + userId() + viewData()?.validate() + validated = true + } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (viewType.asKnown()?.validity() ?: 0) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (options.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + + (viewData.asKnown()?.validity() ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is ObjectType && this.value == other.value + return other is Body && + name == other.name && + objectId == other.objectId && + objectType == other.objectType && + viewType == other.viewType && + deletedAt == other.deletedAt && + options == other.options && + userId == other.userId && + viewData == other.viewData && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash( + name, + objectId, + objectType, + viewType, + deletedAt, + options, + userId, + viewData, + additionalProperties, + ) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, objectId=$objectId, objectType=$objectType, viewType=$viewType, deletedAt=$deletedAt, options=$options, userId=$userId, viewData=$viewData, additionalProperties=$additionalProperties}" + } + + /** Type of table that the view corresponds to. */ + class ViewType @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 { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + val PROJECTS = of("projects") - val PROJECT = ObjectType(JsonField.of("project")) + val EXPERIMENTS = of("experiments") - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + val EXPERIMENT = of("experiment") - val DATASET = ObjectType(JsonField.of("dataset")) + val PLAYGROUNDS = of("playgrounds") - val PROMPT = ObjectType(JsonField.of("prompt")) + val PLAYGROUND = of("playground") - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + val DATASETS = of("datasets") - val GROUP = ObjectType(JsonField.of("group")) + val DATASET = of("dataset") - val ROLE = ObjectType(JsonField.of("role")) + val PROMPTS = of("prompts") - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + val TOOLS = of("tools") - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + val SCORERS = of("scorers") - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + val LOGS = of("logs") - fun of(value: String) = ObjectType(JsonField.of(value)) + fun of(value: String) = ViewType(JsonField.of(value)) } + /** An enum containing [ViewType]'s known values. */ enum class Known { - ORGANIZATION, - PROJECT, + PROJECTS, + EXPERIMENTS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + PROMPTS, + TOOLS, + SCORERS, + LOGS, } + /** + * An enum containing [ViewType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ViewType] 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 { - ORGANIZATION, - PROJECT, + PROJECTS, + EXPERIMENTS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + PROMPTS, + TOOLS, + SCORERS, + LOGS, + /** An enum member indicating that [ViewType] 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) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT + PROJECTS -> Value.PROJECTS + EXPERIMENTS -> Value.EXPERIMENTS EXPERIMENT -> Value.EXPERIMENT + PLAYGROUNDS -> Value.PLAYGROUNDS + PLAYGROUND -> Value.PLAYGROUND + DATASETS -> Value.DATASETS DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT + PROMPTS -> Value.PROMPTS + TOOLS -> Value.TOOLS + SCORERS -> Value.SCORERS + LOGS -> Value.LOGS 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT + PROJECTS -> Known.PROJECTS + EXPERIMENTS -> Known.EXPERIMENTS EXPERIMENT -> Known.EXPERIMENT + PLAYGROUNDS -> Known.PLAYGROUNDS + PLAYGROUND -> Known.PLAYGROUND + DATASETS -> Known.DATASETS DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") + PROMPTS -> Known.PROMPTS + TOOLS -> Known.TOOLS + SCORERS -> Known.SCORERS + LOGS -> Known.LOGS + else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") } - fun asString(): String = _value().asStringOrThrow() - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ViewType = apply { + if (validated) { + return@apply + } - class ViewType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ViewType && this.value == other.value + return other is ViewType && value == other.value } override fun hashCode() = value.hashCode() override fun toString() = value.toString() + } - companion object { - - val PROJECTS = ViewType(JsonField.of("projects")) - - val LOGS = ViewType(JsonField.of("logs")) - - val EXPERIMENTS = ViewType(JsonField.of("experiments")) - - val DATASETS = ViewType(JsonField.of("datasets")) - - val PROMPTS = ViewType(JsonField.of("prompts")) - - val PLAYGROUNDS = ViewType(JsonField.of("playgrounds")) - - val EXPERIMENT = ViewType(JsonField.of("experiment")) - - val DATASET = ViewType(JsonField.of("dataset")) - - fun of(value: String) = ViewType(JsonField.of(value)) - } - - enum class Known { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, - } - - enum class Value { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - PROJECTS -> Value.PROJECTS - LOGS -> Value.LOGS - EXPERIMENTS -> Value.EXPERIMENTS - DATASETS -> Value.DATASETS - PROMPTS -> Value.PROMPTS - PLAYGROUNDS -> Value.PLAYGROUNDS - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - else -> Value._UNKNOWN - } + return other is ViewCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun known(): Known = - when (this) { - PROJECTS -> Known.PROJECTS - LOGS -> Known.LOGS - EXPERIMENTS -> Known.EXPERIMENTS - DATASETS -> Known.DATASETS - PROMPTS -> Known.PROMPTS - PLAYGROUNDS -> Known.PLAYGROUNDS - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "ViewCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewData.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewData.kt index f16e4697..3b2600a2 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewData.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewData.kt @@ -6,98 +6,146 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** The view definition */ -@JsonDeserialize(builder = ViewData.Builder::class) -@NoAutoDetect class ViewData +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val search: JsonField, - private val additionalProperties: Map, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 + @JsonCreator + private constructor( + @JsonProperty("search") @ExcludeMissing search: JsonField = JsonMissing.of() + ) : this(search, mutableMapOf()) + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun search(): ViewDataSearch? = search.getNullable("search") - @JsonProperty("search") @ExcludeMissing fun _search() = search + /** + * Returns the raw JSON value of [search]. + * + * Unlike [search], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("search") @ExcludeMissing fun _search(): JsonField = search + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ViewData = apply { - if (!validated) { - search()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewData && - this.search == other.search && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(search, additionalProperties) - } - return hashCode - } - - override fun toString() = "ViewData{search=$search, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [ViewData]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ViewData]. */ + class Builder internal constructor() { private var search: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(viewData: ViewData) = apply { - this.search = viewData.search - additionalProperties(viewData.additionalProperties) + search = viewData.search + additionalProperties = viewData.additionalProperties.toMutableMap() } - fun search(search: ViewDataSearch) = search(JsonField.of(search)) + fun search(search: ViewDataSearch?) = search(JsonField.ofNullable(search)) - @JsonProperty("search") - @ExcludeMissing + /** + * Sets [Builder.search] to an arbitrary JSON value. + * + * You should usually call [Builder.search] with a well-typed [ViewDataSearch] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun search(search: JsonField) = apply { this.search = search } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): ViewData = ViewData(search, additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ViewData]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ViewData = ViewData(search, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): ViewData = apply { + if (validated) { + return@apply + } + + search()?.validate() + validated = true } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (search.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ViewData && + search == other.search && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(search, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "ViewData{search=$search, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDataSearch.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDataSearch.kt index 6569ff35..e189ab11 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDataSearch.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDataSearch.kt @@ -6,157 +6,309 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects -@JsonDeserialize(builder = ViewDataSearch.Builder::class) -@NoAutoDetect class ViewDataSearch +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val filter: JsonField>, - private val tag: JsonField>, private val match: JsonField>, private val sort: JsonField>, - private val additionalProperties: Map, + private val tag: JsonField>, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - + @JsonCreator + private constructor( + @JsonProperty("filter") + @ExcludeMissing + filter: JsonField> = JsonMissing.of(), + @JsonProperty("match") + @ExcludeMissing + match: JsonField> = JsonMissing.of(), + @JsonProperty("sort") @ExcludeMissing sort: JsonField> = JsonMissing.of(), + @JsonProperty("tag") @ExcludeMissing tag: JsonField> = JsonMissing.of(), + ) : this(filter, match, sort, tag, mutableMapOf()) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun filter(): List? = filter.getNullable("filter") - fun tag(): List? = tag.getNullable("tag") - + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun match(): List? = match.getNullable("match") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun sort(): List? = sort.getNullable("sort") - @JsonProperty("filter") @ExcludeMissing fun _filter() = filter - - @JsonProperty("tag") @ExcludeMissing fun _tag() = tag - - @JsonProperty("match") @ExcludeMissing fun _match() = match + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tag(): List? = tag.getNullable("tag") - @JsonProperty("sort") @ExcludeMissing fun _sort() = sort + /** + * Returns the raw JSON value of [filter]. + * + * Unlike [filter], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("filter") @ExcludeMissing fun _filter(): JsonField> = filter + + /** + * Returns the raw JSON value of [match]. + * + * Unlike [match], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("match") @ExcludeMissing fun _match(): JsonField> = match + + /** + * Returns the raw JSON value of [sort]. + * + * Unlike [sort], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sort") @ExcludeMissing fun _sort(): JsonField> = sort + + /** + * Returns the raw JSON value of [tag]. + * + * Unlike [tag], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tag") @ExcludeMissing fun _tag(): JsonField> = tag + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ViewDataSearch = apply { - if (!validated) { - filter() - tag() - match() - sort() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewDataSearch && - this.filter == other.filter && - this.tag == other.tag && - this.match == other.match && - this.sort == other.sort && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - filter, - tag, - match, - sort, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ViewDataSearch{filter=$filter, tag=$tag, match=$match, sort=$sort, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [ViewDataSearch]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ViewDataSearch]. */ + class Builder internal constructor() { - private var filter: JsonField> = JsonMissing.of() - private var tag: JsonField> = JsonMissing.of() - private var match: JsonField> = JsonMissing.of() - private var sort: JsonField> = JsonMissing.of() + private var filter: JsonField>? = null + private var match: JsonField>? = null + private var sort: JsonField>? = null + private var tag: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() internal fun from(viewDataSearch: ViewDataSearch) = apply { - this.filter = viewDataSearch.filter - this.tag = viewDataSearch.tag - this.match = viewDataSearch.match - this.sort = viewDataSearch.sort - additionalProperties(viewDataSearch.additionalProperties) + filter = viewDataSearch.filter.map { it.toMutableList() } + match = viewDataSearch.match.map { it.toMutableList() } + sort = viewDataSearch.sort.map { it.toMutableList() } + tag = viewDataSearch.tag.map { it.toMutableList() } + additionalProperties = viewDataSearch.additionalProperties.toMutableMap() } - fun filter(filter: List) = filter(JsonField.of(filter)) + fun filter(filter: List?) = filter(JsonField.ofNullable(filter)) + + /** + * Sets [Builder.filter] to an arbitrary JSON value. + * + * You should usually call [Builder.filter] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun filter(filter: JsonField>) = apply { + this.filter = filter.map { it.toMutableList() } + } - @JsonProperty("filter") - @ExcludeMissing - fun filter(filter: JsonField>) = apply { this.filter = filter } + /** + * Adds a single [JsonValue] to [Builder.filter]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFilter(filter: JsonValue) = apply { + this.filter = + (this.filter ?: JsonField.of(mutableListOf())).also { + checkKnown("filter", it).add(filter) + } + } - fun tag(tag: List) = tag(JsonField.of(tag)) + fun match(match: List?) = match(JsonField.ofNullable(match)) + + /** + * Sets [Builder.match] to an arbitrary JSON value. + * + * You should usually call [Builder.match] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun match(match: JsonField>) = apply { + this.match = match.map { it.toMutableList() } + } - @JsonProperty("tag") - @ExcludeMissing - fun tag(tag: JsonField>) = apply { this.tag = tag } + /** + * Adds a single [JsonValue] to [Builder.match]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMatch(match: JsonValue) = apply { + this.match = + (this.match ?: JsonField.of(mutableListOf())).also { + checkKnown("match", it).add(match) + } + } - fun match(match: List) = match(JsonField.of(match)) + fun sort(sort: List?) = sort(JsonField.ofNullable(sort)) + + /** + * Sets [Builder.sort] to an arbitrary JSON value. + * + * You should usually call [Builder.sort] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun sort(sort: JsonField>) = apply { + this.sort = sort.map { it.toMutableList() } + } - @JsonProperty("match") - @ExcludeMissing - fun match(match: JsonField>) = apply { this.match = match } + /** + * Adds a single [JsonValue] to [Builder.sort]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSort(sort: JsonValue) = apply { + this.sort = + (this.sort ?: JsonField.of(mutableListOf())).also { + checkKnown("sort", it).add(sort) + } + } - fun sort(sort: List) = sort(JsonField.of(sort)) + fun tag(tag: List?) = tag(JsonField.ofNullable(tag)) + + /** + * Sets [Builder.tag] to an arbitrary JSON value. + * + * You should usually call [Builder.tag] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun tag(tag: JsonField>) = apply { + this.tag = tag.map { it.toMutableList() } + } - @JsonProperty("sort") - @ExcludeMissing - fun sort(sort: JsonField>) = apply { this.sort = sort } + /** + * Adds a single [JsonValue] to [Builder.tag]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTag(tag: JsonValue) = apply { + this.tag = + (this.tag ?: JsonField.of(mutableListOf())).also { checkKnown("tag", it).add(tag) } + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ViewDataSearch]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ViewDataSearch = ViewDataSearch( - filter.map { it.toUnmodifiable() }, - tag.map { it.toUnmodifiable() }, - match.map { it.toUnmodifiable() }, - sort.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + (filter ?: JsonMissing.of()).map { it.toImmutable() }, + (match ?: JsonMissing.of()).map { it.toImmutable() }, + (sort ?: JsonMissing.of()).map { it.toImmutable() }, + (tag ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), ) } + + private var validated: Boolean = false + + fun validate(): ViewDataSearch = apply { + if (validated) { + return@apply + } + + filter() + match() + sort() + tag() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (filter.asKnown()?.sumOf { (if (it == null) 0 else 1).toInt() } ?: 0) + + (match.asKnown()?.sumOf { (if (it == null) 0 else 1).toInt() } ?: 0) + + (sort.asKnown()?.sumOf { (if (it == null) 0 else 1).toInt() } ?: 0) + + (tag.asKnown()?.sumOf { (if (it == null) 0 else 1).toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ViewDataSearch && + filter == other.filter && + match == other.match && + sort == other.sort && + tag == other.tag && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(filter, match, sort, tag, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ViewDataSearch{filter=$filter, match=$match, sort=$sort, tag=$tag, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDeleteParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDeleteParams.kt index 1ce8af6d..eaa79463 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDeleteParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewDeleteParams.kt @@ -2,395 +2,510 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** Delete a view object by its id */ class ViewDeleteParams -constructor( - private val viewId: String, - private val objectId: String, - private val objectType: ObjectType, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun viewId(): String = viewId - - fun objectId(): String = objectId - - fun objectType(): ObjectType = objectType - - internal fun getBody(): ViewDeleteBody { - return ViewDeleteBody( - objectId, - objectType, - additionalBodyProperties, - ) - } +private constructor( + private val viewId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** View id */ + fun viewId(): String? = viewId + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = body.objectType() + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() + + 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 - internal fun getQueryParams(): Map> = additionalQueryParams + fun toBuilder() = Builder().from(this) - internal fun getHeaders(): Map> = additionalHeaders + companion object { - fun getPathParam(index: Int): String { - return when (index) { - 0 -> viewId - else -> "" - } + /** + * Returns a mutable builder for constructing an instance of [ViewDeleteParams]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - @JsonDeserialize(builder = ViewDeleteBody.Builder::class) - @NoAutoDetect - class ViewDeleteBody - internal constructor( - private val objectId: String?, - private val objectType: ObjectType?, - private val additionalProperties: Map, - ) { + /** A builder for [ViewDeleteParams]. */ + class Builder internal constructor() { - private var hashCode: Int = 0 + private var viewId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - /** The id of the object the view applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + internal fun from(viewDeleteParams: ViewDeleteParams) = apply { + viewId = viewDeleteParams.viewId + body = viewDeleteParams.body.toBuilder() + additionalHeaders = viewDeleteParams.additionalHeaders.toBuilder() + additionalQueryParams = viewDeleteParams.additionalQueryParams.toBuilder() + } - /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + /** View id */ + fun viewId(viewId: String?) = apply { this.viewId = viewId } + + /** + * 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: + * - [objectId] + * - [objectType] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** The id of the object the view applies to */ + fun objectId(objectId: String) = apply { body.objectId(objectId) } - fun toBuilder() = Builder().from(this) + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = apply { body.objectType(objectType) } - return other is ViewDeleteBody && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.additionalProperties == other.additionalProperties - } + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectId, - objectType, - additionalProperties, - ) - } - return hashCode + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) } - override fun toString() = - "ViewDeleteBody{objectId=$objectId, objectType=$objectType, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - class Builder { - - private var objectId: String? = null - private var objectType: ObjectType? = null - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(viewDeleteBody: ViewDeleteBody) = apply { - this.objectId = viewDeleteBody.objectId - this.objectType = viewDeleteBody.objectType - additionalProperties(viewDeleteBody.additionalProperties) - } - - /** The id of the object the view applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } - - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - fun build(): ViewDeleteBody = - ViewDeleteBody( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - additionalProperties.toUnmodifiable(), - ) + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - fun _additionalHeaders(): Map> = additionalHeaders - - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ViewDeleteParams && - this.viewId == other.viewId && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int { - return Objects.hash( - viewId, - objectId, - objectType, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - override fun toString() = - "ViewDeleteParams{viewId=$viewId, objectId=$objectId, objectType=$objectType, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - fun toBuilder() = Builder().from(this) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - companion object { + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - fun builder() = Builder() - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - @NoAutoDetect - class Builder { + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - private var viewId: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - internal fun from(viewDeleteParams: ViewDeleteParams) = apply { - this.viewId = viewDeleteParams.viewId - this.objectId = viewDeleteParams.objectId - this.objectType = viewDeleteParams.objectType - additionalQueryParams(viewDeleteParams.additionalQueryParams) - additionalHeaders(viewDeleteParams.additionalHeaders) - additionalBodyProperties(viewDeleteParams.additionalBodyProperties) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - /** View id */ - fun viewId(viewId: String) = apply { this.viewId = viewId } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The id of the object the view applies to */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - + /** + * Returns an immutable instance of [ViewDeleteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ViewDeleteParams = ViewDeleteParams( - checkNotNull(viewId) { "`viewId` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + viewId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun _body(): Body = body - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun _pathParam(index: Int): String = + when (index) { + 0 -> viewId ?: "" + else -> "" + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val objectId: JsonField, + private val objectType: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + ) : this(objectId, objectType, mutableMapOf()) + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType - return other is ObjectType && this.value == other.value + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode() = value.hashCode() + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = value.toString() + fun toBuilder() = Builder().from(this) companion object { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() + } - val PROJECT = ObjectType(JsonField.of("project")) + /** A builder for [Body]. */ + class Builder internal constructor() { - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() - val DATASET = ObjectType(JsonField.of("dataset")) + internal fun from(body: Body) = apply { + objectId = body.objectId + objectType = body.objectType + additionalProperties = body.additionalProperties.toMutableMap() + } - val PROMPT = ObjectType(JsonField.of("prompt")) + /** The id of the object the view applies to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } + + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - val GROUP = ObjectType(JsonField.of("group")) + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - val ROLE = ObjectType(JsonField.of("role")) + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } - fun of(value: String) = ObjectType(JsonField.of(value)) + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + additionalProperties.toMutableMap(), + ) } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + private var validated: Boolean = false - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, + fun validate(): Body = apply { + if (validated) { + return@apply + } + + objectId() + objectType().validate() + validated = true } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + (objectType.asKnown()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun asString(): String = _value().asStringOrThrow() + return other is Body && + objectId == other.objectId && + objectType == other.objectType && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(objectId, objectType, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{objectId=$objectId, objectType=$objectType, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ViewDeleteParams && + viewId == other.viewId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(viewId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ViewDeleteParams{viewId=$viewId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPage.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPage.kt index 5f656a46..9c9d0e6f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPage.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPage.kt @@ -2,172 +2,120 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPager +import com.braintrustdata.api.core.Page +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.blocking.ViewService -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects +/** @see ViewService.list */ class ViewListPage private constructor( - private val viewsService: ViewService, + private val service: ViewService, private val params: ViewListParams, - private val response: Response, -) { + private val response: ViewListPageResponse, +) : Page { - fun response(): Response = response + /** + * Delegates to [ViewListPageResponse], but gracefully handles missing data. + * + * @see ViewListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewListPage && - this.viewsService == other.viewsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - viewsService, - params, - response, - ) - } - - override fun toString() = - "ViewListPage{viewsService=$viewsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPageParams(): ViewListParams? { - if (!hasNextPage()) { - return null - } - - return if (params.endingBefore() != null) { - ViewListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ViewListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ViewListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - fun getNextPage(): ViewListPage? { - return getNextPageParams()?.let { viewsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(viewsService: ViewService, params: ViewListParams, response: Response) = - ViewListPage( - viewsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override fun nextPage(): ViewListPage = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPager = AutoPager.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ViewListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ViewListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ViewListPage]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ViewListPage]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ViewService? = null + private var params: ViewListParams? = null + private var response: ViewListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(viewListPage: ViewListPage) = apply { + service = viewListPage.service + params = viewListPage.params + response = viewListPage.response } - override fun toString() = - "ViewListPage.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ViewService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ViewListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ViewListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ViewListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ViewListPage = + ViewListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ViewListPage && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ViewListPage, - ) : Sequence { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - yield(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = "ViewListPage{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPageAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPageAsync.kt index 0f9a00f4..92d05304 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPageAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPageAsync.kt @@ -2,174 +2,121 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.ExcludeMissing -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonMissing -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.AutoPagerAsync +import com.braintrustdata.api.core.PageAsync +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.services.async.ViewServiceAsync -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize import java.util.Objects -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector +/** @see ViewServiceAsync.list */ class ViewListPageAsync private constructor( - private val viewsService: ViewServiceAsync, + private val service: ViewServiceAsync, private val params: ViewListParams, - private val response: Response, -) { + private val response: ViewListPageResponse, +) : PageAsync { - fun response(): Response = response + /** + * Delegates to [ViewListPageResponse], but gracefully handles missing data. + * + * @see ViewListPageResponse.objects + */ + fun objects(): List = response._objects().getNullable("objects") ?: emptyList() - fun objects(): List = response().objects() + override fun items(): List = objects() - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewListPageAsync && - this.viewsService == other.viewsService && - this.params == other.params && - this.response == other.response - } - - override fun hashCode(): Int { - return Objects.hash( - viewsService, - params, - response, - ) - } - - override fun toString() = - "ViewListPageAsync{viewsService=$viewsService, params=$params, response=$response}" - - fun hasNextPage(): Boolean { - return !objects().isEmpty() - } - - fun getNextPageParams(): ViewListParams? { - if (!hasNextPage()) { - return null - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return if (params.endingBefore() != null) { - ViewListParams.builder().from(params).endingBefore(objects().first().id()).build() + fun nextPageParams(): ViewListParams = + if (params.endingBefore() != null) { + params.toBuilder().endingBefore(items().first()._id().getNullable("id")).build() } else { - ViewListParams.builder().from(params).startingAfter(objects().last().id()).build() + params.toBuilder().startingAfter(items().last()._id().getNullable("id")).build() } - } - - suspend fun getNextPage(): ViewListPageAsync? { - return getNextPageParams()?.let { viewsService.list(it) } - } - - fun autoPager(): AutoPager = AutoPager(this) - - companion object { - - fun of(viewsService: ViewServiceAsync, params: ViewListParams, response: Response) = - ViewListPageAsync( - viewsService, - params, - response, - ) - } - @JsonDeserialize(builder = Response.Builder::class) - @NoAutoDetect - class Response - constructor( - private val objects: JsonField>, - private val additionalProperties: Map, - ) { + override suspend fun nextPage(): ViewListPageAsync = service.list(nextPageParams()) - private var validated: Boolean = false + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this) - fun objects(): List = objects.getNullable("objects") ?: listOf() + /** The parameters that were used to request this page. */ + fun params(): ViewListParams = params - @JsonProperty("objects") fun _objects(): JsonField>? = objects + /** The response that this page was parsed from. */ + fun response(): ViewListPageResponse = response - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun toBuilder() = Builder().from(this) - fun validate(): Response = apply { - if (!validated) { - objects().map { it.validate() } - validated = true - } - } + companion object { - fun toBuilder() = Builder().from(this) + /** + * Returns a mutable builder for constructing an instance of [ViewListPageAsync]. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + */ + fun builder() = Builder() + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** A builder for [ViewListPageAsync]. */ + class Builder internal constructor() { - return other is Response && - this.objects == other.objects && - this.additionalProperties == other.additionalProperties - } + private var service: ViewServiceAsync? = null + private var params: ViewListParams? = null + private var response: ViewListPageResponse? = null - override fun hashCode(): Int { - return Objects.hash(objects, additionalProperties) + internal fun from(viewListPageAsync: ViewListPageAsync) = apply { + service = viewListPageAsync.service + params = viewListPageAsync.params + response = viewListPageAsync.response } - override fun toString() = - "ViewListPageAsync.Response{objects=$objects, additionalProperties=$additionalProperties}" - - companion object { + fun service(service: ViewServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: ViewListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: ViewListPageResponse) = apply { this.response = response } + + /** + * Returns an immutable instance of [ViewListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ViewListPageAsync = + ViewListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } - fun builder() = Builder() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - class Builder { - - private var objects: JsonField> = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(page: Response) = apply { - this.objects = page.objects - this.additionalProperties.putAll(page.additionalProperties) - } - - fun objects(objects: List) = objects(JsonField.of(objects)) - - @JsonProperty("objects") - fun objects(objects: JsonField>) = apply { this.objects = objects } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun build() = Response(objects, additionalProperties.toUnmodifiable()) - } + return other is ViewListPageAsync && + service == other.service && + params == other.params && + response == other.response } - class AutoPager - constructor( - private val firstPage: ViewListPageAsync, - ) : Flow { - - override suspend fun collect(collector: FlowCollector) { - var page = firstPage - var index = 0 - while (true) { - while (index < page.objects().size) { - collector.emit(page.objects()[index++]) - } - page = page.getNextPage() ?: break - index = 0 - } - } - } + override fun hashCode(): Int = Objects.hash(service, params, response) + + override fun toString() = + "ViewListPageAsync{service=$service, params=$params, response=$response}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPageResponse.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPageResponse.kt new file mode 100644 index 00000000..9c50c46f --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListPageResponse.kt @@ -0,0 +1,189 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.ExcludeMissing +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException +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 ViewListPageResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val objects: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("objects") @ExcludeMissing objects: JsonField> = JsonMissing.of() + ) : this(objects, mutableMapOf()) + + /** + * A list of view objects + * + * @throws BraintrustInvalidDataException 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 objects(): List = objects.getRequired("objects") + + /** + * Returns the raw JSON value of [objects]. + * + * Unlike [objects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("objects") @ExcludeMissing fun _objects(): JsonField> = objects + + @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 [ViewListPageResponse]. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + */ + fun builder() = Builder() + } + + /** A builder for [ViewListPageResponse]. */ + class Builder internal constructor() { + + private var objects: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + internal fun from(viewListPageResponse: ViewListPageResponse) = apply { + objects = viewListPageResponse.objects.map { it.toMutableList() } + additionalProperties = viewListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of view objects */ + fun objects(objects: List) = objects(JsonField.of(objects)) + + /** + * Sets [Builder.objects] to an arbitrary JSON value. + * + * You should usually call [Builder.objects] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun objects(objects: JsonField>) = apply { + this.objects = objects.map { it.toMutableList() } + } + + /** + * Adds a single [View] to [objects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addObject(object_: View) = apply { + objects = + (objects ?: JsonField.of(mutableListOf())).also { + checkKnown("objects", it).add(object_) + } + } + + 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 [ViewListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objects() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ViewListPageResponse = + ViewListPageResponse( + checkRequired("objects", objects).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ViewListPageResponse = apply { + if (validated) { + return@apply + } + + objects().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = (objects.asKnown()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ViewListPageResponse && + objects == other.objects && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(objects, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ViewListPageResponse{objects=$objects, additionalProperties=$additionalProperties}" +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListParams.kt index 2b7255dd..d5f78b9c 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewListParams.kt @@ -2,151 +2,125 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.BaseDeserializer -import com.braintrustdata.api.core.BaseSerializer -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired import com.braintrustdata.api.core.getOrThrow -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -import com.fasterxml.jackson.annotation.JsonCreator -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.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams +import com.braintrustdata.api.core.toImmutable import java.util.Objects +/** + * List out all views. The views are sorted by creation date, with the most recently-created views + * coming first + */ class ViewListParams -constructor( +private constructor( private val objectId: String, - private val objectType: ObjectType, + private val objectType: AclObjectType, private val endingBefore: String?, private val ids: Ids?, private val limit: Long?, private val startingAfter: String?, private val viewName: String?, private val viewType: ViewType?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + /** The id of the object the ACL applies to */ fun objectId(): String = objectId - fun objectType(): ObjectType = objectType + /** The object type that the ACL applies to */ + fun objectType(): AclObjectType = objectType + /** + * Pagination cursor id. + * + * For example, if the initial item in the last page you fetched had an id of `foo`, pass + * `ending_before=foo` to fetch the previous page. Note: you may only pass one of + * `starting_after` and `ending_before` + */ fun endingBefore(): String? = endingBefore + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ fun ids(): Ids? = ids + /** Limit the number of objects to return */ fun limit(): Long? = limit + /** + * Pagination cursor id. + * + * For example, if the final item in the last page you fetched had an id of `foo`, pass + * `starting_after=foo` to fetch the next page. Note: you may only pass one of `starting_after` + * and `ending_before` + */ fun startingAfter(): String? = startingAfter + /** Name of the view to search for */ fun viewName(): String? = viewName + /** Type of table that the view corresponds to. */ fun viewType(): ViewType? = viewType - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.objectId.let { params.put("object_id", listOf(it.toString())) } - this.objectType.let { params.put("object_type", listOf(it.toString())) } - this.endingBefore?.let { params.put("ending_before", listOf(it.toString())) } - this.ids?.let { params.put("ids", listOf(it.toString())) } - this.limit?.let { params.put("limit", listOf(it.toString())) } - this.startingAfter?.let { params.put("starting_after", listOf(it.toString())) } - this.viewName?.let { params.put("view_name", listOf(it.toString())) } - this.viewType?.let { params.put("view_type", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewListParams && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.endingBefore == other.endingBefore && - this.ids == other.ids && - this.limit == other.limit && - this.startingAfter == other.startingAfter && - this.viewName == other.viewName && - this.viewType == other.viewType && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - objectId, - objectType, - endingBefore, - ids, - limit, - startingAfter, - viewName, - viewType, - additionalQueryParams, - additionalHeaders, - ) - } + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - override fun toString() = - "ViewListParams{objectId=$objectId, objectType=$objectType, endingBefore=$endingBefore, ids=$ids, limit=$limit, startingAfter=$startingAfter, viewName=$viewName, viewType=$viewType, additionalQueryParams=$additionalQueryParams, additionalHeaders=$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 [ViewListParams]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ViewListParams]. */ + class Builder internal constructor() { private var objectId: String? = null - private var objectType: ObjectType? = null + private var objectType: AclObjectType? = null private var endingBefore: String? = null private var ids: Ids? = null private var limit: Long? = null private var startingAfter: String? = null private var viewName: String? = null private var viewType: ViewType? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(viewListParams: ViewListParams) = apply { - this.objectId = viewListParams.objectId - this.objectType = viewListParams.objectType - this.endingBefore = viewListParams.endingBefore - this.ids = viewListParams.ids - this.limit = viewListParams.limit - this.startingAfter = viewListParams.startingAfter - this.viewName = viewListParams.viewName - this.viewType = viewListParams.viewType - additionalQueryParams(viewListParams.additionalQueryParams) - additionalHeaders(viewListParams.additionalHeaders) + objectId = viewListParams.objectId + objectType = viewListParams.objectType + endingBefore = viewListParams.endingBefore + ids = viewListParams.ids + limit = viewListParams.limit + startingAfter = viewListParams.startingAfter + viewName = viewListParams.viewName + viewType = viewListParams.viewType + additionalHeaders = viewListParams.additionalHeaders.toBuilder() + additionalQueryParams = viewListParams.additionalQueryParams.toBuilder() } /** The id of the object the ACL applies to */ fun objectId(objectId: String) = apply { this.objectId = objectId } /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun objectType(objectType: AclObjectType) = apply { this.objectType = objectType } /** * Pagination cursor id. @@ -155,28 +129,29 @@ constructor( * `ending_before=foo` to fetch the previous page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun endingBefore(endingBefore: String) = apply { this.endingBefore = endingBefore } + fun endingBefore(endingBefore: String?) = apply { this.endingBefore = endingBefore } /** * Filter search results to a particular set of object IDs. To specify a list of IDs, * include the query param multiple times */ - fun ids(ids: Ids) = apply { this.ids = ids } + fun ids(ids: Ids?) = apply { this.ids = ids } - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(string: String) = apply { this.ids = Ids.ofString(string) } + /** Alias for calling [ids] with `Ids.ofString(string)`. */ + fun ids(string: String) = ids(Ids.ofString(string)) - /** - * Filter search results to a particular set of object IDs. To specify a list of IDs, - * include the query param multiple times - */ - fun ids(strings: List) = apply { this.ids = Ids.ofStrings(strings) } + /** Alias for calling [ids] with `Ids.ofStrings(strings)`. */ + fun idsOfStrings(strings: List) = ids(Ids.ofStrings(strings)) /** Limit the number of objects to return */ - fun limit(limit: Long) = apply { this.limit = limit } + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) /** * Pagination cursor id. @@ -185,191 +160,177 @@ constructor( * `starting_after=foo` to fetch the next page. Note: you may only pass one of * `starting_after` and `ending_before` */ - fun startingAfter(startingAfter: String) = apply { this.startingAfter = startingAfter } + fun startingAfter(startingAfter: String?) = apply { this.startingAfter = startingAfter } /** Name of the view to search for */ - fun viewName(viewName: String) = apply { this.viewName = viewName } + fun viewName(viewName: String?) = apply { this.viewName = viewName } /** Type of table that the view corresponds to. */ - fun viewType(viewType: ViewType) = apply { this.viewType = viewType } + fun viewType(viewType: ViewType?) = apply { this.viewType = viewType } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } - - fun build(): ViewListParams = - ViewListParams( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - endingBefore, - ids, - limit, - startingAfter, - viewName, - viewType, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) - } - - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ObjectType && this.value == other.value + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) - - val PROJECT = ObjectType(JsonField.of("project")) - - val EXPERIMENT = ObjectType(JsonField.of("experiment")) - - val DATASET = ObjectType(JsonField.of("dataset")) + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - val PROMPT = ObjectType(JsonField.of("prompt")) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - val GROUP = ObjectType(JsonField.of("group")) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - val ROLE = ObjectType(JsonField.of("role")) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun of(value: String) = ObjectType(JsonField.of(value)) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - fun asString(): String = _value().asStringOrThrow() + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [ViewListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ViewListParams = + ViewListParams( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + endingBefore, + ids, + limit, + startingAfter, + viewName, + viewType, + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - @JsonDeserialize(using = Ids.Deserializer::class) - @JsonSerialize(using = Ids.Serializer::class) + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + put("object_id", objectId) + put("object_type", objectType.toString()) + endingBefore?.let { put("ending_before", it) } + ids?.accept( + object : Ids.Visitor { + override fun visitString(string: String) { + put("ids", string) + } + + override fun visitStrings(strings: List) { + put("ids", strings.joinToString(",")) + } + } + ) + limit?.let { put("limit", it.toString()) } + startingAfter?.let { put("starting_after", it) } + viewName?.let { put("view_name", it) } + viewType?.let { put("view_type", it.toString()) } + putAll(additionalQueryParams) + } + .build() + + /** + * Filter search results to a particular set of object IDs. To specify a list of IDs, include + * the query param multiple times + */ class Ids private constructor( private val string: String? = null, private val strings: List? = null, - private val _json: JsonValue? = null, ) { - private var validated: Boolean = false - fun string(): String? = string fun strings(): List? = strings @@ -382,186 +343,78 @@ constructor( fun asStrings(): List = strings.getOrThrow("strings") - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { + fun accept(visitor: Visitor): T = + when { string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) - else -> visitor.unknown(_json) - } - } - - fun validate(): Ids = apply { - if (!validated) { - if (string == null && strings == null) { - throw BraintrustInvalidDataException("Unknown Ids: $_json") - } - validated = true + else -> throw IllegalStateException("Invalid Ids") } - } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Ids && this.string == other.string && this.strings == other.strings + return other is Ids && string == other.string && strings == other.strings } - override fun hashCode(): Int { - return Objects.hash(string, strings) - } + override fun hashCode(): Int = Objects.hash(string, strings) - override fun toString(): String { - return when { + override fun toString(): String = + when { string != null -> "Ids{string=$string}" strings != null -> "Ids{strings=$strings}" - _json != null -> "Ids{_unknown=$_json}" else -> throw IllegalStateException("Invalid Ids") } - } companion object { fun ofString(string: String) = Ids(string = string) - fun ofStrings(strings: List) = Ids(strings = strings) + fun ofStrings(strings: List) = Ids(strings = strings.toImmutable()) } + /** An interface that defines how to map each variant of [Ids] to a value of type [T]. */ interface Visitor { fun visitString(string: String): T fun visitStrings(strings: List): T - - fun unknown(json: JsonValue?): T { - throw BraintrustInvalidDataException("Unknown Ids: $json") - } - } - - class Deserializer : BaseDeserializer(Ids::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Ids { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Ids(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef>())?.let { - return Ids(strings = it, _json = json) - } - - return Ids(_json = json) - } - } - - class Serializer : BaseSerializer(Ids::class) { - - override fun serialize( - value: Ids, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.strings != null -> generator.writeObject(value.strings) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Ids") - } - } } } - class ViewType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewType && this.value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val PROJECTS = ViewType(JsonField.of("projects")) - - val LOGS = ViewType(JsonField.of("logs")) - - val EXPERIMENTS = ViewType(JsonField.of("experiments")) - - val DATASETS = ViewType(JsonField.of("datasets")) - - val PROMPTS = ViewType(JsonField.of("prompts")) - - val PLAYGROUNDS = ViewType(JsonField.of("playgrounds")) - - val EXPERIMENT = ViewType(JsonField.of("experiment")) - - val DATASET = ViewType(JsonField.of("dataset")) - - fun of(value: String) = ViewType(JsonField.of(value)) - } - - enum class Known { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, - } - - enum class Value { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - PROJECTS -> Value.PROJECTS - LOGS -> Value.LOGS - EXPERIMENTS -> Value.EXPERIMENTS - DATASETS -> Value.DATASETS - PROMPTS -> Value.PROMPTS - PLAYGROUNDS -> Value.PLAYGROUNDS - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - else -> Value._UNKNOWN - } + return other is ViewListParams && + objectId == other.objectId && + objectType == other.objectType && + endingBefore == other.endingBefore && + ids == other.ids && + limit == other.limit && + startingAfter == other.startingAfter && + viewName == other.viewName && + viewType == other.viewType && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun known(): Known = - when (this) { - PROJECTS -> Known.PROJECTS - LOGS -> Known.LOGS - EXPERIMENTS -> Known.EXPERIMENTS - DATASETS -> Known.DATASETS - PROMPTS -> Known.PROMPTS - PLAYGROUNDS -> Known.PLAYGROUNDS - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") - } + override fun hashCode(): Int = + Objects.hash( + objectId, + objectType, + endingBefore, + ids, + limit, + startingAfter, + viewName, + viewType, + additionalHeaders, + additionalQueryParams, + ) - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "ViewListParams{objectId=$objectId, objectType=$objectType, endingBefore=$endingBefore, ids=$ids, limit=$limit, startingAfter=$startingAfter, viewName=$viewName, viewType=$viewType, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewOptions.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewOptions.kt index 8bceb058..9f4ad24a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewOptions.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewOptions.kt @@ -6,291 +6,557 @@ import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.checkKnown +import com.braintrustdata.api.core.toImmutable +import com.braintrustdata.api.errors.BraintrustInvalidDataException 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects /** Options for the view in the app */ -@JsonDeserialize(builder = ViewOptions.Builder::class) -@NoAutoDetect class ViewOptions +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val columnVisibility: JsonField, private val columnOrder: JsonField>, private val columnSizing: JsonField, - private val additionalProperties: Map, + private val columnVisibility: JsonField, + private val grouping: JsonField, + private val layout: JsonField, + private val rowHeight: JsonField, + private val additionalProperties: MutableMap, ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun columnVisibility(): ColumnVisibility? = columnVisibility.getNullable("columnVisibility") - + @JsonCreator + private constructor( + @JsonProperty("columnOrder") + @ExcludeMissing + columnOrder: JsonField> = JsonMissing.of(), + @JsonProperty("columnSizing") + @ExcludeMissing + columnSizing: JsonField = JsonMissing.of(), + @JsonProperty("columnVisibility") + @ExcludeMissing + columnVisibility: JsonField = JsonMissing.of(), + @JsonProperty("grouping") @ExcludeMissing grouping: JsonField = JsonMissing.of(), + @JsonProperty("layout") @ExcludeMissing layout: JsonField = JsonMissing.of(), + @JsonProperty("rowHeight") @ExcludeMissing rowHeight: JsonField = JsonMissing.of(), + ) : this( + columnOrder, + columnSizing, + columnVisibility, + grouping, + layout, + rowHeight, + mutableMapOf(), + ) + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun columnOrder(): List? = columnOrder.getNullable("columnOrder") + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ fun columnSizing(): ColumnSizing? = columnSizing.getNullable("columnSizing") - @JsonProperty("columnVisibility") @ExcludeMissing fun _columnVisibility() = columnVisibility - - @JsonProperty("columnOrder") @ExcludeMissing fun _columnOrder() = columnOrder + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun columnVisibility(): ColumnVisibility? = columnVisibility.getNullable("columnVisibility") - @JsonProperty("columnSizing") @ExcludeMissing fun _columnSizing() = columnSizing + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun grouping(): String? = grouping.getNullable("grouping") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun layout(): String? = layout.getNullable("layout") + + /** + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun rowHeight(): String? = rowHeight.getNullable("rowHeight") + + /** + * Returns the raw JSON value of [columnOrder]. + * + * Unlike [columnOrder], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("columnOrder") + @ExcludeMissing + fun _columnOrder(): JsonField> = columnOrder + + /** + * Returns the raw JSON value of [columnSizing]. + * + * Unlike [columnSizing], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("columnSizing") + @ExcludeMissing + fun _columnSizing(): JsonField = columnSizing + + /** + * Returns the raw JSON value of [columnVisibility]. + * + * Unlike [columnVisibility], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("columnVisibility") + @ExcludeMissing + fun _columnVisibility(): JsonField = columnVisibility + + /** + * Returns the raw JSON value of [grouping]. + * + * Unlike [grouping], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("grouping") @ExcludeMissing fun _grouping(): JsonField = grouping + + /** + * Returns the raw JSON value of [layout]. + * + * Unlike [layout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("layout") @ExcludeMissing fun _layout(): JsonField = layout + + /** + * Returns the raw JSON value of [rowHeight]. + * + * Unlike [rowHeight], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("rowHeight") @ExcludeMissing fun _rowHeight(): JsonField = rowHeight + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate(): ViewOptions = apply { - if (!validated) { - columnVisibility()?.validate() - columnOrder() - columnSizing()?.validate() - validated = true - } - } + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewOptions && - this.columnVisibility == other.columnVisibility && - this.columnOrder == other.columnOrder && - this.columnSizing == other.columnSizing && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - columnVisibility, - columnOrder, - columnSizing, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "ViewOptions{columnVisibility=$columnVisibility, columnOrder=$columnOrder, columnSizing=$columnSizing, additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [ViewOptions]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ViewOptions]. */ + class Builder internal constructor() { - private var columnVisibility: JsonField = JsonMissing.of() - private var columnOrder: JsonField> = JsonMissing.of() + private var columnOrder: JsonField>? = null private var columnSizing: JsonField = JsonMissing.of() + private var columnVisibility: JsonField = JsonMissing.of() + private var grouping: JsonField = JsonMissing.of() + private var layout: JsonField = JsonMissing.of() + private var rowHeight: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() internal fun from(viewOptions: ViewOptions) = apply { - this.columnVisibility = viewOptions.columnVisibility - this.columnOrder = viewOptions.columnOrder - this.columnSizing = viewOptions.columnSizing - additionalProperties(viewOptions.additionalProperties) + columnOrder = viewOptions.columnOrder.map { it.toMutableList() } + columnSizing = viewOptions.columnSizing + columnVisibility = viewOptions.columnVisibility + grouping = viewOptions.grouping + layout = viewOptions.layout + rowHeight = viewOptions.rowHeight + additionalProperties = viewOptions.additionalProperties.toMutableMap() } - fun columnVisibility(columnVisibility: ColumnVisibility) = - columnVisibility(JsonField.of(columnVisibility)) + fun columnOrder(columnOrder: List?) = columnOrder(JsonField.ofNullable(columnOrder)) - @JsonProperty("columnVisibility") - @ExcludeMissing - fun columnVisibility(columnVisibility: JsonField) = apply { - this.columnVisibility = columnVisibility + /** + * Sets [Builder.columnOrder] to an arbitrary JSON value. + * + * You should usually call [Builder.columnOrder] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun columnOrder(columnOrder: JsonField>) = apply { + this.columnOrder = columnOrder.map { it.toMutableList() } } - fun columnOrder(columnOrder: List) = columnOrder(JsonField.of(columnOrder)) - - @JsonProperty("columnOrder") - @ExcludeMissing - fun columnOrder(columnOrder: JsonField>) = apply { - this.columnOrder = columnOrder + /** + * Adds a single [String] to [Builder.columnOrder]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addColumnOrder(columnOrder: String) = apply { + this.columnOrder = + (this.columnOrder ?: JsonField.of(mutableListOf())).also { + checkKnown("columnOrder", it).add(columnOrder) + } } - fun columnSizing(columnSizing: ColumnSizing) = columnSizing(JsonField.of(columnSizing)) + fun columnSizing(columnSizing: ColumnSizing?) = + columnSizing(JsonField.ofNullable(columnSizing)) - @JsonProperty("columnSizing") - @ExcludeMissing + /** + * Sets [Builder.columnSizing] to an arbitrary JSON value. + * + * You should usually call [Builder.columnSizing] with a well-typed [ColumnSizing] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun columnSizing(columnSizing: JsonField) = apply { this.columnSizing = columnSizing } + fun columnVisibility(columnVisibility: ColumnVisibility?) = + columnVisibility(JsonField.ofNullable(columnVisibility)) + + /** + * Sets [Builder.columnVisibility] to an arbitrary JSON value. + * + * You should usually call [Builder.columnVisibility] with a well-typed [ColumnVisibility] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun columnVisibility(columnVisibility: JsonField) = apply { + this.columnVisibility = columnVisibility + } + + fun grouping(grouping: String?) = grouping(JsonField.ofNullable(grouping)) + + /** + * Sets [Builder.grouping] to an arbitrary JSON value. + * + * You should usually call [Builder.grouping] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun grouping(grouping: JsonField) = apply { this.grouping = grouping } + + fun layout(layout: String?) = layout(JsonField.ofNullable(layout)) + + /** + * Sets [Builder.layout] to an arbitrary JSON value. + * + * You should usually call [Builder.layout] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun layout(layout: JsonField) = apply { this.layout = layout } + + fun rowHeight(rowHeight: String?) = rowHeight(JsonField.ofNullable(rowHeight)) + + /** + * Sets [Builder.rowHeight] to an arbitrary JSON value. + * + * You should usually call [Builder.rowHeight] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun rowHeight(rowHeight: JsonField) = apply { this.rowHeight = rowHeight } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + 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 [ViewOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ fun build(): ViewOptions = ViewOptions( - columnVisibility, - columnOrder.map { it.toUnmodifiable() }, + (columnOrder ?: JsonMissing.of()).map { it.toImmutable() }, columnSizing, - additionalProperties.toUnmodifiable(), + columnVisibility, + grouping, + layout, + rowHeight, + additionalProperties.toMutableMap(), ) } - @JsonDeserialize(builder = ColumnSizing.Builder::class) - @NoAutoDetect + private var validated: Boolean = false + + fun validate(): ViewOptions = apply { + if (validated) { + return@apply + } + + columnOrder() + columnSizing()?.validate() + columnVisibility()?.validate() + grouping() + layout() + rowHeight() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (columnOrder.asKnown()?.size ?: 0) + + (columnSizing.asKnown()?.validity() ?: 0) + + (columnVisibility.asKnown()?.validity() ?: 0) + + (if (grouping.asKnown() == null) 0 else 1) + + (if (layout.asKnown() == null) 0 else 1) + + (if (rowHeight.asKnown() == null) 0 else 1) + class ColumnSizing + @JsonCreator private constructor( - private val additionalProperties: Map, + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - @JsonAnyGetter @ExcludeMissing fun _additionalProperties(): Map = additionalProperties - fun validate(): ColumnSizing = apply { - if (!validated) { - validated = true - } - } - fun toBuilder() = Builder().from(this) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ColumnSizing && this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } - - override fun toString() = "ColumnSizing{additionalProperties=$additionalProperties}" - companion object { + /** Returns a mutable builder for constructing an instance of [ColumnSizing]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ColumnSizing]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(columnSizing: ColumnSizing) = apply { - additionalProperties(columnSizing.additionalProperties) + additionalProperties = columnSizing.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): ColumnSizing = ColumnSizing(additionalProperties.toUnmodifiable()) - } - } + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - @JsonDeserialize(builder = ColumnVisibility.Builder::class) - @NoAutoDetect - class ColumnVisibility - private constructor( - private val additionalProperties: Map, - ) { + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ColumnSizing]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ColumnSizing = ColumnSizing(additionalProperties.toImmutable()) + } private var validated: Boolean = false - private var hashCode: Int = 0 + fun validate(): ColumnSizing = apply { + if (validated) { + return@apply + } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + validated = true + } - fun validate(): ColumnVisibility = apply { - if (!validated) { - validated = true + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false } - } - fun toBuilder() = Builder().from(this) + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ColumnVisibility && - this.additionalProperties == other.additionalProperties + return other is ColumnSizing && additionalProperties == other.additionalProperties } - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = Objects.hash(additionalProperties) - } - return hashCode - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - override fun toString() = "ColumnVisibility{additionalProperties=$additionalProperties}" + override fun hashCode(): Int = hashCode + + override fun toString() = "ColumnSizing{additionalProperties=$additionalProperties}" + } + + class ColumnVisibility + @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 [ColumnVisibility]. */ fun builder() = Builder() } - class Builder { + /** A builder for [ColumnVisibility]. */ + class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() internal fun from(columnVisibility: ColumnVisibility) = apply { - additionalProperties(columnVisibility.additionalProperties) + additionalProperties = columnVisibility.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) + putAllAdditionalProperties(additionalProperties) } - @JsonAnySetter fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + additionalProperties.put(key, value) } fun putAllAdditionalProperties(additionalProperties: Map) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): ColumnVisibility = ColumnVisibility(additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ColumnVisibility]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ColumnVisibility = ColumnVisibility(additionalProperties.toImmutable()) } + + private var validated: Boolean = false + + fun validate(): ColumnVisibility = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ColumnVisibility && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "ColumnVisibility{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ViewOptions && + columnOrder == other.columnOrder && + columnSizing == other.columnSizing && + columnVisibility == other.columnVisibility && + grouping == other.grouping && + layout == other.layout && + rowHeight == other.rowHeight && + additionalProperties == other.additionalProperties } + + private val hashCode: Int by lazy { + Objects.hash( + columnOrder, + columnSizing, + columnVisibility, + grouping, + layout, + rowHeight, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ViewOptions{columnOrder=$columnOrder, columnSizing=$columnSizing, columnVisibility=$columnVisibility, grouping=$grouping, layout=$layout, rowHeight=$rowHeight, additionalProperties=$additionalProperties}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewReplaceParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewReplaceParams.kt index d43ef204..be1d35a4 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewReplaceParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewReplaceParams.kt @@ -5,268 +5,481 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize import java.time.OffsetDateTime +import java.util.Collections import java.util.Objects +/** + * Create or replace view. If there is an existing view with the same name as the one specified in + * the request, will replace the existing view with the provided fields + */ class ViewReplaceParams -constructor( - private val name: String, - private val objectId: String, - private val objectType: ObjectType, - private val viewType: ViewType?, - private val deletedAt: OffsetDateTime?, - private val options: ViewOptions?, - private val userId: String?, - private val viewData: ViewData?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Name of the view + * + * @throws BraintrustInvalidDataException 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 name(): String = body.name() + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = body.objectType() + + /** + * Type of table that the view corresponds to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun viewType(): ViewType? = body.viewType() + + /** + * Date of role deletion, or null if the role is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun deletedAt(): OffsetDateTime? = body.deletedAt() + + /** + * Options for the view in the app + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): ViewOptions? = body.options() + + /** + * Identifies the user who created the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = body.userId() + + /** + * The view definition + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun viewData(): ViewData? = body.viewData() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() + + /** + * Returns the raw JSON value of [viewType]. + * + * Unlike [viewType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _viewType(): JsonField = body._viewType() + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _deletedAt(): JsonField = body._deletedAt() + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _userId(): JsonField = body._userId() + + /** + * Returns the raw JSON value of [viewData]. + * + * Unlike [viewData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _viewData(): JsonField = body._viewData() + + 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 name(): String = name - - fun objectId(): String = objectId - - fun objectType(): ObjectType = objectType - - fun viewType(): ViewType? = viewType - - fun deletedAt(): OffsetDateTime? = deletedAt + fun toBuilder() = Builder().from(this) - fun options(): ViewOptions? = options + companion object { - fun userId(): String? = userId + /** + * Returns a mutable builder for constructing an instance of [ViewReplaceParams]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + */ + fun builder() = Builder() + } - fun viewData(): ViewData? = viewData + /** A builder for [ViewReplaceParams]. */ + class Builder internal constructor() { - internal fun getBody(): ViewReplaceBody { - return ViewReplaceBody( - name, - objectId, - objectType, - viewType, - deletedAt, - options, - userId, - viewData, - additionalBodyProperties, - ) - } + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - internal fun getQueryParams(): Map> = additionalQueryParams - - internal fun getHeaders(): Map> = additionalHeaders - - @JsonDeserialize(builder = ViewReplaceBody.Builder::class) - @NoAutoDetect - class ViewReplaceBody - internal constructor( - private val name: String?, - private val objectId: String?, - private val objectType: ObjectType?, - private val viewType: ViewType?, - private val deletedAt: OffsetDateTime?, - private val options: ViewOptions?, - private val userId: String?, - private val viewData: ViewData?, - private val additionalProperties: Map, - ) { + internal fun from(viewReplaceParams: ViewReplaceParams) = apply { + body = viewReplaceParams.body.toBuilder() + additionalHeaders = viewReplaceParams.additionalHeaders.toBuilder() + additionalQueryParams = viewReplaceParams.additionalQueryParams.toBuilder() + } - private var hashCode: Int = 0 + /** + * 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: + * - [name] + * - [objectId] + * - [objectType] + * - [viewType] + * - [deletedAt] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** Name of the view */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** The id of the object the view applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + fun objectId(objectId: String) = apply { body.objectId(objectId) } + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + fun objectType(objectType: AclObjectType) = apply { body.objectType(objectType) } + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") fun viewType(): ViewType? = viewType + fun viewType(viewType: ViewType?) = apply { body.viewType(viewType) } + + /** + * Sets [Builder.viewType] to an arbitrary JSON value. + * + * You should usually call [Builder.viewType] with a well-typed [ViewType] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewType(viewType: JsonField) = apply { body.viewType(viewType) } /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") fun deletedAt(): OffsetDateTime? = deletedAt + fun deletedAt(deletedAt: OffsetDateTime?) = apply { body.deletedAt(deletedAt) } + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { body.deletedAt(deletedAt) } /** Options for the view in the app */ - @JsonProperty("options") fun options(): ViewOptions? = options + fun options(options: ViewOptions?) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [ViewOptions] 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) } /** Identifies the user who created the view */ - @JsonProperty("user_id") fun userId(): String? = userId + fun userId(userId: String?) = apply { body.userId(userId) } + + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { body.userId(userId) } /** The view definition */ - @JsonProperty("view_data") fun viewData(): ViewData? = viewData + fun viewData(viewData: ViewData?) = apply { body.viewData(viewData) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.viewData] to an arbitrary JSON value. + * + * You should usually call [Builder.viewData] with a well-typed [ViewData] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewData(viewData: JsonField) = apply { body.viewData(viewData) } - fun toBuilder() = Builder().from(this) + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } - return other is ViewReplaceBody && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.viewType == other.viewType && - this.deletedAt == other.deletedAt && - this.options == other.options && - this.userId == other.userId && - this.viewData == other.viewData && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - name, - objectId, - objectType, - viewType, - deletedAt, - options, - userId, - viewData, - additionalProperties, - ) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - return hashCode + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - override fun toString() = - "ViewReplaceBody{name=$name, objectId=$objectId, objectType=$objectType, viewType=$viewType, deletedAt=$deletedAt, options=$options, userId=$userId, viewData=$viewData, additionalProperties=$additionalProperties}" + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - companion object { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - fun builder() = Builder() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - class Builder { + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var viewType: ViewType? = null - private var deletedAt: OffsetDateTime? = null - private var options: ViewOptions? = null - private var userId: String? = null - private var viewData: ViewData? = null - private var additionalProperties: MutableMap = mutableMapOf() + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - internal fun from(viewReplaceBody: ViewReplaceBody) = apply { - this.name = viewReplaceBody.name - this.objectId = viewReplaceBody.objectId - this.objectType = viewReplaceBody.objectType - this.viewType = viewReplaceBody.viewType - this.deletedAt = viewReplaceBody.deletedAt - this.options = viewReplaceBody.options - this.userId = viewReplaceBody.userId - this.viewData = viewReplaceBody.viewData - additionalProperties(viewReplaceBody.additionalProperties) - } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** Name of the view */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** The id of the object the view applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") - fun viewType(viewType: ViewType) = apply { this.viewType = viewType } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Date of role deletion, or null if the role is still active */ - @JsonProperty("deleted_at") - fun deletedAt(deletedAt: OffsetDateTime) = apply { this.deletedAt = deletedAt } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** Options for the view in the app */ - @JsonProperty("options") - fun options(options: ViewOptions) = apply { this.options = options } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - /** Identifies the user who created the view */ - @JsonProperty("user_id") fun userId(userId: String) = apply { this.userId = userId } + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - /** The view definition */ - @JsonProperty("view_data") - fun viewData(viewData: ViewData) = apply { this.viewData = viewData } + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun build(): ViewReplaceBody = - ViewReplaceBody( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - viewType, - deletedAt, - options, - userId, - viewData, - additionalProperties.toUnmodifiable(), - ) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalHeaders(): Map> = additionalHeaders + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - return other is ViewReplaceParams && - this.name == other.name && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.viewType == other.viewType && - this.deletedAt == other.deletedAt && - this.options == other.options && - this.userId == other.userId && - this.viewData == other.viewData && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties + /** + * Returns an immutable instance of [ViewReplaceParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ViewReplaceParams = + ViewReplaceParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) } - override fun hashCode(): Int { - return Objects.hash( + 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 name: JsonField, + private val objectId: JsonField, + private val objectType: JsonField, + private val viewType: JsonField, + private val deletedAt: JsonField, + private val options: JsonField, + private val userId: JsonField, + private val viewData: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("view_type") + @ExcludeMissing + viewType: JsonField = JsonMissing.of(), + @JsonProperty("deleted_at") + @ExcludeMissing + deletedAt: JsonField = JsonMissing.of(), + @JsonProperty("options") + @ExcludeMissing + options: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + @JsonProperty("view_data") + @ExcludeMissing + viewData: JsonField = JsonMissing.of(), + ) : this( name, objectId, objectType, @@ -275,346 +488,606 @@ constructor( options, userId, viewData, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, + mutableMapOf(), ) - } - - override fun toString() = - "ViewReplaceParams{name=$name, objectId=$objectId, objectType=$objectType, viewType=$viewType, deletedAt=$deletedAt, options=$options, userId=$userId, viewData=$viewData, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - fun toBuilder() = Builder().from(this) + /** + * Name of the view + * + * @throws BraintrustInvalidDataException 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 name(): String = name.getRequired("name") + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") + + /** + * Type of table that the view corresponds to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewType(): ViewType? = viewType.getNullable("view_type") + + /** + * Date of role deletion, or null if the role is still active + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun deletedAt(): OffsetDateTime? = deletedAt.getNullable("deleted_at") + + /** + * Options for the view in the app + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): ViewOptions? = options.getNullable("options") + + /** + * Identifies the user who created the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") + + /** + * The view definition + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewData(): ViewData? = viewData.getNullable("view_data") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [viewType]. + * + * Unlike [viewType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_type") @ExcludeMissing fun _viewType(): JsonField = viewType + + /** + * Returns the raw JSON value of [deletedAt]. + * + * Unlike [deletedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("deleted_at") + @ExcludeMissing + fun _deletedAt(): JsonField = deletedAt + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + /** + * Returns the raw JSON value of [viewData]. + * + * Unlike [viewData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_data") @ExcludeMissing fun _viewData(): JsonField = viewData + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - companion object { + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun builder() = Builder() - } + fun toBuilder() = Builder().from(this) - @NoAutoDetect - class Builder { - - private var name: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var viewType: ViewType? = null - private var deletedAt: OffsetDateTime? = null - private var options: ViewOptions? = null - private var userId: String? = null - private var viewData: ViewData? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + companion object { - internal fun from(viewReplaceParams: ViewReplaceParams) = apply { - this.name = viewReplaceParams.name - this.objectId = viewReplaceParams.objectId - this.objectType = viewReplaceParams.objectType - this.viewType = viewReplaceParams.viewType - this.deletedAt = viewReplaceParams.deletedAt - this.options = viewReplaceParams.options - this.userId = viewReplaceParams.userId - this.viewData = viewReplaceParams.viewData - additionalQueryParams(viewReplaceParams.additionalQueryParams) - additionalHeaders(viewReplaceParams.additionalHeaders) - additionalBodyProperties(viewReplaceParams.additionalBodyProperties) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + */ + fun builder() = Builder() } - /** Name of the view */ - fun name(name: String) = apply { this.name = name } + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var viewType: JsonField? = null + private var deletedAt: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() + private var viewData: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** The id of the object the view applies to */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + internal fun from(body: Body) = apply { + name = body.name + objectId = body.objectId + objectType = body.objectType + viewType = body.viewType + deletedAt = body.deletedAt + options = body.options + userId = body.userId + viewData = body.viewData + additionalProperties = body.additionalProperties.toMutableMap() + } - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + /** Name of the view */ + fun name(name: String) = name(JsonField.of(name)) - /** Type of table that the view corresponds to. */ - fun viewType(viewType: ViewType) = apply { this.viewType = viewType } + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - /** Date of role deletion, or null if the role is still active */ - fun deletedAt(deletedAt: OffsetDateTime) = apply { this.deletedAt = deletedAt } + /** The id of the object the view applies to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - /** Options for the view in the app */ - fun options(options: ViewOptions) = apply { this.options = options } + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - /** Identifies the user who created the view */ - fun userId(userId: String) = apply { this.userId = userId } + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - /** The view definition */ - fun viewData(viewData: ViewData) = apply { this.viewData = viewData } + /** Type of table that the view corresponds to. */ + fun viewType(viewType: ViewType?) = viewType(JsonField.ofNullable(viewType)) - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) - } + /** + * Sets [Builder.viewType] to an arbitrary JSON value. + * + * You should usually call [Builder.viewType] with a well-typed [ViewType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun viewType(viewType: JsonField) = apply { this.viewType = viewType } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) - } + /** Date of role deletion, or null if the role is still active */ + fun deletedAt(deletedAt: OffsetDateTime?) = deletedAt(JsonField.ofNullable(deletedAt)) + + /** + * Sets [Builder.deletedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.deletedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun deletedAt(deletedAt: JsonField) = apply { + this.deletedAt = deletedAt + } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** Options for the view in the app */ + fun options(options: ViewOptions?) = options(JsonField.ofNullable(options)) - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) - } + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [ViewOptions] 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 removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) - } + /** Identifies the user who created the view */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) - } + /** The view definition */ + fun viewData(viewData: ViewData?) = viewData(JsonField.ofNullable(viewData)) - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) - } + /** + * Sets [Builder.viewData] to an arbitrary JSON value. + * + * You should usually call [Builder.viewData] with a well-typed [ViewData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun viewData(viewData: JsonField) = apply { this.viewData = viewData } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + 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: + * ```kotlin + * .name() + * .objectId() + * .objectType() + * .viewType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("name", name), + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + checkRequired("viewType", viewType), + deletedAt, + options, + userId, + viewData, + additionalProperties.toMutableMap(), + ) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply } - fun build(): ViewReplaceParams = - ViewReplaceParams( - checkNotNull(name) { "`name` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - viewType, - deletedAt, - options, - userId, - viewData, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), - ) - } + name() + objectId() + objectType().validate() + viewType()?.validate() + deletedAt() + options()?.validate() + userId() + viewData()?.validate() + validated = true + } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (name.asKnown() == null) 0 else 1) + + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (viewType.asKnown()?.validity() ?: 0) + + (if (deletedAt.asKnown() == null) 0 else 1) + + (options.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + + (viewData.asKnown()?.validity() ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is ObjectType && this.value == other.value + return other is Body && + name == other.name && + objectId == other.objectId && + objectType == other.objectType && + viewType == other.viewType && + deletedAt == other.deletedAt && + options == other.options && + userId == other.userId && + viewData == other.viewData && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash( + name, + objectId, + objectType, + viewType, + deletedAt, + options, + userId, + viewData, + additionalProperties, + ) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{name=$name, objectId=$objectId, objectType=$objectType, viewType=$viewType, deletedAt=$deletedAt, options=$options, userId=$userId, viewData=$viewData, additionalProperties=$additionalProperties}" + } + + /** Type of table that the view corresponds to. */ + class ViewType @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 { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + val PROJECTS = of("projects") - val PROJECT = ObjectType(JsonField.of("project")) + val EXPERIMENTS = of("experiments") - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + val EXPERIMENT = of("experiment") - val DATASET = ObjectType(JsonField.of("dataset")) + val PLAYGROUNDS = of("playgrounds") - val PROMPT = ObjectType(JsonField.of("prompt")) + val PLAYGROUND = of("playground") - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + val DATASETS = of("datasets") - val GROUP = ObjectType(JsonField.of("group")) + val DATASET = of("dataset") - val ROLE = ObjectType(JsonField.of("role")) + val PROMPTS = of("prompts") - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + val TOOLS = of("tools") - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + val SCORERS = of("scorers") - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + val LOGS = of("logs") - fun of(value: String) = ObjectType(JsonField.of(value)) + fun of(value: String) = ViewType(JsonField.of(value)) } + /** An enum containing [ViewType]'s known values. */ enum class Known { - ORGANIZATION, - PROJECT, + PROJECTS, + EXPERIMENTS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + PROMPTS, + TOOLS, + SCORERS, + LOGS, } + /** + * An enum containing [ViewType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ViewType] 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 { - ORGANIZATION, - PROJECT, + PROJECTS, + EXPERIMENTS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + PROMPTS, + TOOLS, + SCORERS, + LOGS, + /** An enum member indicating that [ViewType] 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) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT + PROJECTS -> Value.PROJECTS + EXPERIMENTS -> Value.EXPERIMENTS EXPERIMENT -> Value.EXPERIMENT + PLAYGROUNDS -> Value.PLAYGROUNDS + PLAYGROUND -> Value.PLAYGROUND + DATASETS -> Value.DATASETS DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT + PROMPTS -> Value.PROMPTS + TOOLS -> Value.TOOLS + SCORERS -> Value.SCORERS + LOGS -> Value.LOGS 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT + PROJECTS -> Known.PROJECTS + EXPERIMENTS -> Known.EXPERIMENTS EXPERIMENT -> Known.EXPERIMENT + PLAYGROUNDS -> Known.PLAYGROUNDS + PLAYGROUND -> Known.PLAYGROUND + DATASETS -> Known.DATASETS DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") + PROMPTS -> Known.PROMPTS + TOOLS -> Known.TOOLS + SCORERS -> Known.SCORERS + LOGS -> Known.LOGS + else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") } - fun asString(): String = _value().asStringOrThrow() - } + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ViewType = apply { + if (validated) { + return@apply + } - class ViewType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + known() + validated = true + } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ViewType && this.value == other.value + return other is ViewType && value == other.value } override fun hashCode() = value.hashCode() override fun toString() = value.toString() + } - companion object { - - val PROJECTS = ViewType(JsonField.of("projects")) - - val LOGS = ViewType(JsonField.of("logs")) - - val EXPERIMENTS = ViewType(JsonField.of("experiments")) - - val DATASETS = ViewType(JsonField.of("datasets")) - - val PROMPTS = ViewType(JsonField.of("prompts")) - - val PLAYGROUNDS = ViewType(JsonField.of("playgrounds")) - - val EXPERIMENT = ViewType(JsonField.of("experiment")) - - val DATASET = ViewType(JsonField.of("dataset")) - - fun of(value: String) = ViewType(JsonField.of(value)) - } - - enum class Known { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, - } - - enum class Value { - PROJECTS, - LOGS, - EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, - EXPERIMENT, - DATASET, - _UNKNOWN, + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - fun value(): Value = - when (this) { - PROJECTS -> Value.PROJECTS - LOGS -> Value.LOGS - EXPERIMENTS -> Value.EXPERIMENTS - DATASETS -> Value.DATASETS - PROMPTS -> Value.PROMPTS - PLAYGROUNDS -> Value.PLAYGROUNDS - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - else -> Value._UNKNOWN - } + return other is ViewReplaceParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } - fun known(): Known = - when (this) { - PROJECTS -> Known.PROJECTS - LOGS -> Known.LOGS - EXPERIMENTS -> Known.EXPERIMENTS - DATASETS -> Known.DATASETS - PROMPTS -> Known.PROMPTS - PLAYGROUNDS -> Known.PLAYGROUNDS - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") - } + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) - fun asString(): String = _value().asStringOrThrow() - } + override fun toString() = + "ViewReplaceParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewRetrieveParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewRetrieveParams.kt index 61640f9c..76062638 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewRetrieveParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewRetrieveParams.kt @@ -2,269 +2,233 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.JsonField -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable -import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* -import com.fasterxml.jackson.annotation.JsonCreator +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import java.util.Objects +/** Get a view object by its id */ class ViewRetrieveParams -constructor( - private val viewId: String, +private constructor( + private val viewId: String?, private val objectId: String, - private val objectType: ObjectType, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, -) { + private val objectType: AclObjectType, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { - fun viewId(): String = viewId + /** View id */ + fun viewId(): String? = viewId + /** The id of the object the ACL applies to */ fun objectId(): String = objectId - fun objectType(): ObjectType = objectType + /** The object type that the ACL applies to */ + fun objectType(): AclObjectType = objectType - internal fun getQueryParams(): Map> { - val params = mutableMapOf>() - this.objectId.let { params.put("object_id", listOf(it.toString())) } - this.objectType.let { params.put("object_type", listOf(it.toString())) } - params.putAll(additionalQueryParams) - return params.toUnmodifiable() - } - - internal fun getHeaders(): Map> = additionalHeaders + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders - fun getPathParam(index: Int): String { - return when (index) { - 0 -> viewId - else -> "" - } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ViewRetrieveParams && - this.viewId == other.viewId && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders - } - - override fun hashCode(): Int { - return Objects.hash( - viewId, - objectId, - objectType, - additionalQueryParams, - additionalHeaders, - ) - } - - override fun toString() = - "ViewRetrieveParams{viewId=$viewId, objectId=$objectId, objectType=$objectType, additionalQueryParams=$additionalQueryParams, additionalHeaders=$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 [ViewRetrieveParams]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ fun builder() = Builder() } - @NoAutoDetect - class Builder { + /** A builder for [ViewRetrieveParams]. */ + class Builder internal constructor() { private var viewId: String? = null private var objectId: String? = null - private var objectType: ObjectType? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() + private var objectType: AclObjectType? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() internal fun from(viewRetrieveParams: ViewRetrieveParams) = apply { - this.viewId = viewRetrieveParams.viewId - this.objectId = viewRetrieveParams.objectId - this.objectType = viewRetrieveParams.objectType - additionalQueryParams(viewRetrieveParams.additionalQueryParams) - additionalHeaders(viewRetrieveParams.additionalHeaders) + viewId = viewRetrieveParams.viewId + objectId = viewRetrieveParams.objectId + objectType = viewRetrieveParams.objectType + additionalHeaders = viewRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = viewRetrieveParams.additionalQueryParams.toBuilder() } /** View id */ - fun viewId(viewId: String) = apply { this.viewId = viewId } + fun viewId(viewId: String?) = apply { this.viewId = viewId } /** The id of the object the ACL applies to */ fun objectId(objectId: String) = apply { this.objectId = objectId } /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun objectType(objectType: AclObjectType) = apply { this.objectType = objectType } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } - - fun build(): ViewRetrieveParams = - ViewRetrieveParams( - checkNotNull(viewId) { "`viewId` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - ) - } - - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { - - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ObjectType && this.value == other.value + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - companion object { - - val ORGANIZATION = ObjectType(JsonField.of("organization")) + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - val PROJECT = ObjectType(JsonField.of("project")) + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } - val DATASET = ObjectType(JsonField.of("dataset")) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } - val PROMPT = ObjectType(JsonField.of("prompt")) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - val GROUP = ObjectType(JsonField.of("group")) + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - val ROLE = ObjectType(JsonField.of("role")) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun of(value: String) = ObjectType(JsonField.of(value)) - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [ViewRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ViewRetrieveParams = + ViewRetrieveParams( + viewId, + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, + fun _pathParam(index: Int): String = + when (index) { + 0 -> viewId ?: "" + else -> "" } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + override fun _headers(): Headers = additionalHeaders - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + put("object_id", objectId) + put("object_type", objectType.toString()) + putAll(additionalQueryParams) } + .build() - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") - } + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - fun asString(): String = _value().asStringOrThrow() + return other is ViewRetrieveParams && + viewId == other.viewId && + objectId == other.objectId && + objectType == other.objectType && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(viewId, objectId, objectType, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ViewRetrieveParams{viewId=$viewId, objectId=$objectId, objectType=$objectType, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewType.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewType.kt new file mode 100644 index 00000000..9e3b46cf --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewType.kt @@ -0,0 +1,186 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.Enum +import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.errors.BraintrustInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator + +/** Type of table that the view corresponds to. */ +class ViewType @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 { + + val PROJECTS = of("projects") + + val EXPERIMENTS = of("experiments") + + val EXPERIMENT = of("experiment") + + val PLAYGROUNDS = of("playgrounds") + + val PLAYGROUND = of("playground") + + val DATASETS = of("datasets") + + val DATASET = of("dataset") + + val PROMPTS = of("prompts") + + val TOOLS = of("tools") + + val SCORERS = of("scorers") + + val LOGS = of("logs") + + fun of(value: String) = ViewType(JsonField.of(value)) + } + + /** An enum containing [ViewType]'s known values. */ + enum class Known { + PROJECTS, + EXPERIMENTS, + EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, + DATASET, + PROMPTS, + TOOLS, + SCORERS, + LOGS, + } + + /** + * An enum containing [ViewType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ViewType] 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 { + PROJECTS, + EXPERIMENTS, + EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, + DATASET, + PROMPTS, + TOOLS, + SCORERS, + LOGS, + /** An enum member indicating that [ViewType] 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) { + PROJECTS -> Value.PROJECTS + EXPERIMENTS -> Value.EXPERIMENTS + EXPERIMENT -> Value.EXPERIMENT + PLAYGROUNDS -> Value.PLAYGROUNDS + PLAYGROUND -> Value.PLAYGROUND + DATASETS -> Value.DATASETS + DATASET -> Value.DATASET + PROMPTS -> Value.PROMPTS + TOOLS -> Value.TOOLS + SCORERS -> Value.SCORERS + LOGS -> Value.LOGS + 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + PROJECTS -> Known.PROJECTS + EXPERIMENTS -> Known.EXPERIMENTS + EXPERIMENT -> Known.EXPERIMENT + PLAYGROUNDS -> Known.PLAYGROUNDS + PLAYGROUND -> Known.PLAYGROUND + DATASETS -> Known.DATASETS + DATASET -> Known.DATASET + PROMPTS -> Known.PROMPTS + TOOLS -> Known.TOOLS + SCORERS -> Known.SCORERS + LOGS -> Known.LOGS + else -> throw BraintrustInvalidDataException("Unknown ViewType: $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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ViewType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + 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 ViewType && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewUpdateParams.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewUpdateParams.kt index aa48e052..a2899aba 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewUpdateParams.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/models/ViewUpdateParams.kt @@ -5,608 +5,1020 @@ package com.braintrustdata.api.models import com.braintrustdata.api.core.Enum import com.braintrustdata.api.core.ExcludeMissing import com.braintrustdata.api.core.JsonField +import com.braintrustdata.api.core.JsonMissing import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.NoAutoDetect -import com.braintrustdata.api.core.toUnmodifiable +import com.braintrustdata.api.core.Params +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.http.Headers +import com.braintrustdata.api.core.http.QueryParams import com.braintrustdata.api.errors.BraintrustInvalidDataException -import com.braintrustdata.api.models.* 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.databind.annotation.JsonDeserialize +import java.util.Collections import java.util.Objects +/** + * Partially update a view object. Specify the fields to update in the payload. Any object-type + * fields will be deep-merged with existing content. Currently we do not support removing fields or + * setting them to null. + */ class ViewUpdateParams -constructor( - private val viewId: String, - private val objectId: String, - private val objectType: ObjectType, - private val name: String?, - private val options: ViewOptions?, - private val userId: String?, - private val viewData: ViewData?, - private val viewType: ViewType?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, - private val additionalBodyProperties: Map, -) { - - fun viewId(): String = viewId - - fun objectId(): String = objectId - - fun objectType(): ObjectType = objectType - - fun name(): String? = name - - fun options(): ViewOptions? = options - - fun userId(): String? = userId - - fun viewData(): ViewData? = viewData - - fun viewType(): ViewType? = viewType - - internal fun getBody(): ViewUpdateBody { - return ViewUpdateBody( - objectId, - objectType, - name, - options, - userId, - viewData, - viewType, - additionalBodyProperties, - ) - } +private constructor( + private val viewId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** View id */ + fun viewId(): String? = viewId + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = body.objectId() + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = body.objectType() + + /** + * Name of the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): String? = body.name() + + /** + * Options for the view in the app + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): ViewOptions? = body.options() + + /** + * Identifies the user who created the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userId(): String? = body.userId() + + /** + * The view definition + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun viewData(): ViewData? = body.viewData() + + /** + * Type of table that the view corresponds to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun viewType(): ViewType? = body.viewType() + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectId(): JsonField = body._objectId() + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _objectType(): JsonField = body._objectType() + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _userId(): JsonField = body._userId() + + /** + * Returns the raw JSON value of [viewData]. + * + * Unlike [viewData], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _viewData(): JsonField = body._viewData() + + /** + * Returns the raw JSON value of [viewType]. + * + * Unlike [viewType], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _viewType(): JsonField = body._viewType() + + 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 - internal fun getQueryParams(): Map> = additionalQueryParams + fun toBuilder() = Builder().from(this) - internal fun getHeaders(): Map> = additionalHeaders + companion object { - fun getPathParam(index: Int): String { - return when (index) { - 0 -> viewId - else -> "" - } + /** + * Returns a mutable builder for constructing an instance of [ViewUpdateParams]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() } - @JsonDeserialize(builder = ViewUpdateBody.Builder::class) - @NoAutoDetect - class ViewUpdateBody - internal constructor( - private val objectId: String?, - private val objectType: ObjectType?, - private val name: String?, - private val options: ViewOptions?, - private val userId: String?, - private val viewData: ViewData?, - private val viewType: ViewType?, - private val additionalProperties: Map, - ) { + /** A builder for [ViewUpdateParams]. */ + class Builder internal constructor() { - private var hashCode: Int = 0 + private var viewId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + internal fun from(viewUpdateParams: ViewUpdateParams) = apply { + viewId = viewUpdateParams.viewId + body = viewUpdateParams.body.toBuilder() + additionalHeaders = viewUpdateParams.additionalHeaders.toBuilder() + additionalQueryParams = viewUpdateParams.additionalQueryParams.toBuilder() + } + + /** View id */ + fun viewId(viewId: String?) = apply { this.viewId = viewId } + + /** + * 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: + * - [objectId] + * - [objectType] + * - [name] + * - [options] + * - [userId] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } /** The id of the object the view applies to */ - @JsonProperty("object_id") fun objectId(): String? = objectId + fun objectId(objectId: String) = apply { body.objectId(objectId) } + + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun objectId(objectId: JsonField) = apply { body.objectId(objectId) } /** The object type that the ACL applies to */ - @JsonProperty("object_type") fun objectType(): ObjectType? = objectType + fun objectType(objectType: AclObjectType) = apply { body.objectType(objectType) } + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { body.objectType(objectType) } /** Name of the view */ - @JsonProperty("name") fun name(): String? = name + fun name(name: String?) = apply { body.name(name) } + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } /** Options for the view in the app */ - @JsonProperty("options") fun options(): ViewOptions? = options + fun options(options: ViewOptions?) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [ViewOptions] 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) } /** Identifies the user who created the view */ - @JsonProperty("user_id") fun userId(): String? = userId + fun userId(userId: String?) = apply { body.userId(userId) } - /** The view definition */ - @JsonProperty("view_data") fun viewData(): ViewData? = viewData + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun userId(userId: JsonField) = apply { body.userId(userId) } - /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") fun viewType(): ViewType? = viewType + /** The view definition */ + fun viewData(viewData: ViewData?) = apply { body.viewData(viewData) } - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + /** + * Sets [Builder.viewData] to an arbitrary JSON value. + * + * You should usually call [Builder.viewData] with a well-typed [ViewData] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewData(viewData: JsonField) = apply { body.viewData(viewData) } - fun toBuilder() = Builder().from(this) + /** Type of table that the view corresponds to. */ + fun viewType(viewType: ViewType?) = apply { body.viewType(viewType) } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + /** + * Sets [Builder.viewType] to an arbitrary JSON value. + * + * You should usually call [Builder.viewType] with a well-typed [ViewType] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewType(viewType: JsonField) = apply { body.viewType(viewType) } - return other is ViewUpdateBody && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.name == other.name && - this.options == other.options && - this.userId == other.userId && - this.viewData == other.viewData && - this.viewType == other.viewType && - this.additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - objectId, - objectType, - name, - options, - userId, - viewData, - viewType, - additionalProperties, - ) - } - return hashCode + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) } - override fun toString() = - "ViewUpdateBody{objectId=$objectId, objectType=$objectType, name=$name, options=$options, userId=$userId, viewData=$viewData, viewType=$viewType, additionalProperties=$additionalProperties}" - - companion object { - - fun builder() = Builder() + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) } - class Builder { - - private var objectId: String? = null - private var objectType: ObjectType? = null - private var name: String? = null - private var options: ViewOptions? = null - private var userId: String? = null - private var viewData: ViewData? = null - private var viewType: ViewType? = null - private var additionalProperties: MutableMap = mutableMapOf() - - internal fun from(viewUpdateBody: ViewUpdateBody) = apply { - this.objectId = viewUpdateBody.objectId - this.objectType = viewUpdateBody.objectType - this.name = viewUpdateBody.name - this.options = viewUpdateBody.options - this.userId = viewUpdateBody.userId - this.viewData = viewUpdateBody.viewData - this.viewType = viewUpdateBody.viewType - additionalProperties(viewUpdateBody.additionalProperties) - } - - /** The id of the object the view applies to */ - @JsonProperty("object_id") - fun objectId(objectId: String) = apply { this.objectId = objectId } - - /** The object type that the ACL applies to */ - @JsonProperty("object_type") - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } - - /** Name of the view */ - @JsonProperty("name") fun name(name: String) = apply { this.name = name } - - /** Options for the view in the app */ - @JsonProperty("options") - fun options(options: ViewOptions) = apply { this.options = options } - - /** Identifies the user who created the view */ - @JsonProperty("user_id") fun userId(userId: String) = apply { this.userId = userId } - - /** The view definition */ - @JsonProperty("view_data") - fun viewData(viewData: ViewData) = apply { this.viewData = viewData } - - /** Type of table that the view corresponds to. */ - @JsonProperty("view_type") - fun viewType(viewType: ViewType) = apply { this.viewType = viewType } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - fun build(): ViewUpdateBody = - ViewUpdateBody( - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - name, - options, - userId, - viewData, - viewType, - additionalProperties.toUnmodifiable(), - ) + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) } - } - - fun _additionalQueryParams(): Map> = additionalQueryParams - - fun _additionalHeaders(): Map> = additionalHeaders - fun _additionalBodyProperties(): Map = additionalBodyProperties - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) } - return other is ViewUpdateParams && - this.viewId == other.viewId && - this.objectId == other.objectId && - this.objectType == other.objectType && - this.name == other.name && - this.options == other.options && - this.userId == other.userId && - this.viewData == other.viewData && - this.viewType == other.viewType && - this.additionalQueryParams == other.additionalQueryParams && - this.additionalHeaders == other.additionalHeaders && - this.additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int { - return Objects.hash( - viewId, - objectId, - objectType, - name, - options, - userId, - viewData, - viewType, - additionalQueryParams, - additionalHeaders, - additionalBodyProperties, - ) - } - - override fun toString() = - "ViewUpdateParams{viewId=$viewId, objectId=$objectId, objectType=$objectType, name=$name, options=$options, userId=$userId, viewData=$viewData, viewType=$viewType, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" - - fun toBuilder() = Builder().from(this) - - companion object { - - fun builder() = Builder() - } - - @NoAutoDetect - class Builder { + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } - private var viewId: String? = null - private var objectId: String? = null - private var objectType: ObjectType? = null - private var name: String? = null - private var options: ViewOptions? = null - private var userId: String? = null - private var viewData: ViewData? = null - private var viewType: ViewType? = null - private var additionalQueryParams: MutableMap> = mutableMapOf() - private var additionalHeaders: MutableMap> = mutableMapOf() - private var additionalBodyProperties: MutableMap = mutableMapOf() + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } - internal fun from(viewUpdateParams: ViewUpdateParams) = apply { - this.viewId = viewUpdateParams.viewId - this.objectId = viewUpdateParams.objectId - this.objectType = viewUpdateParams.objectType - this.name = viewUpdateParams.name - this.options = viewUpdateParams.options - this.userId = viewUpdateParams.userId - this.viewData = viewUpdateParams.viewData - this.viewType = viewUpdateParams.viewType - additionalQueryParams(viewUpdateParams.additionalQueryParams) - additionalHeaders(viewUpdateParams.additionalHeaders) - additionalBodyProperties(viewUpdateParams.additionalBodyProperties) + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) } - /** View id */ - fun viewId(viewId: String) = apply { this.viewId = viewId } + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** The id of the object the view applies to */ - fun objectId(objectId: String) = apply { this.objectId = objectId } + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } - /** The object type that the ACL applies to */ - fun objectType(objectType: ObjectType) = apply { this.objectType = objectType } + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } - /** Name of the view */ - fun name(name: String) = apply { this.name = name } + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } - /** Options for the view in the app */ - fun options(options: ViewOptions) = apply { this.options = options } + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** Identifies the user who created the view */ - fun userId(userId: String) = apply { this.userId = userId } + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } - /** The view definition */ - fun viewData(viewData: ViewData) = apply { this.viewData = viewData } + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - /** Type of table that the view corresponds to. */ - fun viewType(viewType: ViewType) = apply { this.viewType = viewType } + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } - fun additionalQueryParams(additionalQueryParams: Map>) = apply { + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { this.additionalQueryParams.clear() - putAllQueryParams(additionalQueryParams) + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParam(name: String, value: String) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.add(value) + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) } - fun putQueryParams(name: String, values: Iterable) = apply { - this.additionalQueryParams.getOrPut(name) { mutableListOf() }.addAll(values) + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) } - fun putAllQueryParams(additionalQueryParams: Map>) = apply { - additionalQueryParams.forEach(this::putQueryParams) + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) } - fun removeQueryParam(name: String) = apply { - this.additionalQueryParams.put(name, mutableListOf()) + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) } - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllHeaders(additionalHeaders) - } + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } - fun putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) } - fun putHeaders(name: String, values: Iterable) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.addAll(values) + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) } - fun putAllHeaders(additionalHeaders: Map>) = apply { - additionalHeaders.forEach(this::putHeaders) + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) } - fun removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - this.additionalBodyProperties.putAll(additionalBodyProperties) - } + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - this.additionalBodyProperties.put(key, value) + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) } - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - + /** + * Returns an immutable instance of [ViewUpdateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ fun build(): ViewUpdateParams = ViewUpdateParams( - checkNotNull(viewId) { "`viewId` is required but was not set" }, - checkNotNull(objectId) { "`objectId` is required but was not set" }, - checkNotNull(objectType) { "`objectType` is required but was not set" }, - name, - options, - userId, - viewData, - viewType, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + viewId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), ) } - class ObjectType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun _body(): Body = body - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + fun _pathParam(index: Int): String = + when (index) { + 0 -> viewId ?: "" + else -> "" + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val objectId: JsonField, + private val objectType: JsonField, + private val name: JsonField, + private val options: JsonField, + private val userId: JsonField, + private val viewData: JsonField, + private val viewType: JsonField, + private val additionalProperties: MutableMap, + ) { - return other is ObjectType && this.value == other.value + @JsonCreator + private constructor( + @JsonProperty("object_id") + @ExcludeMissing + objectId: JsonField = JsonMissing.of(), + @JsonProperty("object_type") + @ExcludeMissing + objectType: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("options") + @ExcludeMissing + options: JsonField = JsonMissing.of(), + @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), + @JsonProperty("view_data") + @ExcludeMissing + viewData: JsonField = JsonMissing.of(), + @JsonProperty("view_type") + @ExcludeMissing + viewType: JsonField = JsonMissing.of(), + ) : this(objectId, objectType, name, options, userId, viewData, viewType, mutableMapOf()) + + /** + * The id of the object the view applies to + * + * @throws BraintrustInvalidDataException 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 objectId(): String = objectId.getRequired("object_id") + + /** + * The object type that the ACL applies to + * + * @throws BraintrustInvalidDataException 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 objectType(): AclObjectType = objectType.getRequired("object_type") + + /** + * Name of the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun name(): String? = name.getNullable("name") + + /** + * Options for the view in the app + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): ViewOptions? = options.getNullable("options") + + /** + * Identifies the user who created the view + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun userId(): String? = userId.getNullable("user_id") + + /** + * The view definition + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewData(): ViewData? = viewData.getNullable("view_data") + + /** + * Type of table that the view corresponds to. + * + * @throws BraintrustInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewType(): ViewType? = viewType.getNullable("view_type") + + /** + * Returns the raw JSON value of [objectId]. + * + * Unlike [objectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_id") @ExcludeMissing fun _objectId(): JsonField = objectId + + /** + * Returns the raw JSON value of [objectType]. + * + * Unlike [objectType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object_type") + @ExcludeMissing + fun _objectType(): JsonField = objectType + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * 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 [userId]. + * + * Unlike [userId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + + /** + * Returns the raw JSON value of [viewData]. + * + * Unlike [viewData], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_data") @ExcludeMissing fun _viewData(): JsonField = viewData + + /** + * Returns the raw JSON value of [viewType]. + * + * Unlike [viewType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("view_type") @ExcludeMissing fun _viewType(): JsonField = viewType + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) } - override fun hashCode() = value.hashCode() + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun toString() = value.toString() + fun toBuilder() = Builder().from(this) companion object { - val ORGANIZATION = ObjectType(JsonField.of("organization")) + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```kotlin + * .objectId() + * .objectType() + * ``` + */ + fun builder() = Builder() + } - val PROJECT = ObjectType(JsonField.of("project")) + /** A builder for [Body]. */ + class Builder internal constructor() { - val EXPERIMENT = ObjectType(JsonField.of("experiment")) + private var objectId: JsonField? = null + private var objectType: JsonField? = null + private var name: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var userId: JsonField = JsonMissing.of() + private var viewData: JsonField = JsonMissing.of() + private var viewType: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - val DATASET = ObjectType(JsonField.of("dataset")) + internal fun from(body: Body) = apply { + objectId = body.objectId + objectType = body.objectType + name = body.name + options = body.options + userId = body.userId + viewData = body.viewData + viewType = body.viewType + additionalProperties = body.additionalProperties.toMutableMap() + } - val PROMPT = ObjectType(JsonField.of("prompt")) + /** The id of the object the view applies to */ + fun objectId(objectId: String) = objectId(JsonField.of(objectId)) - val PROMPT_SESSION = ObjectType(JsonField.of("prompt_session")) + /** + * Sets [Builder.objectId] to an arbitrary JSON value. + * + * You should usually call [Builder.objectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectId(objectId: JsonField) = apply { this.objectId = objectId } - val GROUP = ObjectType(JsonField.of("group")) + /** The object type that the ACL applies to */ + fun objectType(objectType: AclObjectType) = objectType(JsonField.of(objectType)) + + /** + * Sets [Builder.objectType] to an arbitrary JSON value. + * + * You should usually call [Builder.objectType] with a well-typed [AclObjectType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun objectType(objectType: JsonField) = apply { + this.objectType = objectType + } - val ROLE = ObjectType(JsonField.of("role")) + /** Name of the view */ + fun name(name: String?) = name(JsonField.ofNullable(name)) - val ORG_MEMBER = ObjectType(JsonField.of("org_member")) + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } - val PROJECT_LOG = ObjectType(JsonField.of("project_log")) + /** Options for the view in the app */ + fun options(options: ViewOptions?) = options(JsonField.ofNullable(options)) - val ORG_PROJECT = ObjectType(JsonField.of("org_project")) + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [ViewOptions] 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 of(value: String) = ObjectType(JsonField.of(value)) - } + /** Identifies the user who created the view */ + fun userId(userId: String?) = userId(JsonField.ofNullable(userId)) - enum class Known { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - } + /** + * Sets [Builder.userId] to an arbitrary JSON value. + * + * You should usually call [Builder.userId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userId(userId: JsonField) = apply { this.userId = userId } - enum class Value { - ORGANIZATION, - PROJECT, - EXPERIMENT, - DATASET, - PROMPT, - PROMPT_SESSION, - GROUP, - ROLE, - ORG_MEMBER, - PROJECT_LOG, - ORG_PROJECT, - _UNKNOWN, - } + /** The view definition */ + fun viewData(viewData: ViewData?) = viewData(JsonField.ofNullable(viewData)) - fun value(): Value = - when (this) { - ORGANIZATION -> Value.ORGANIZATION - PROJECT -> Value.PROJECT - EXPERIMENT -> Value.EXPERIMENT - DATASET -> Value.DATASET - PROMPT -> Value.PROMPT - PROMPT_SESSION -> Value.PROMPT_SESSION - GROUP -> Value.GROUP - ROLE -> Value.ROLE - ORG_MEMBER -> Value.ORG_MEMBER - PROJECT_LOG -> Value.PROJECT_LOG - ORG_PROJECT -> Value.ORG_PROJECT - else -> Value._UNKNOWN + /** + * Sets [Builder.viewData] to an arbitrary JSON value. + * + * You should usually call [Builder.viewData] with a well-typed [ViewData] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun viewData(viewData: JsonField) = apply { this.viewData = viewData } + + /** Type of table that the view corresponds to. */ + fun viewType(viewType: ViewType?) = viewType(JsonField.ofNullable(viewType)) + + /** + * Sets [Builder.viewType] to an arbitrary JSON value. + * + * You should usually call [Builder.viewType] with a well-typed [ViewType] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun viewType(viewType: JsonField) = apply { this.viewType = viewType } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } - fun known(): Known = - when (this) { - ORGANIZATION -> Known.ORGANIZATION - PROJECT -> Known.PROJECT - EXPERIMENT -> Known.EXPERIMENT - DATASET -> Known.DATASET - PROMPT -> Known.PROMPT - PROMPT_SESSION -> Known.PROMPT_SESSION - GROUP -> Known.GROUP - ROLE -> Known.ROLE - ORG_MEMBER -> Known.ORG_MEMBER - PROJECT_LOG -> Known.PROJECT_LOG - ORG_PROJECT -> Known.ORG_PROJECT - else -> throw BraintrustInvalidDataException("Unknown ObjectType: $value") + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) } - fun asString(): String = _value().asStringOrThrow() - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - class ViewType - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + 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: + * ```kotlin + * .objectId() + * .objectType() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("objectId", objectId), + checkRequired("objectType", objectType), + name, + options, + userId, + viewData, + viewType, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + objectId() + objectType().validate() + name() + options()?.validate() + userId() + viewData()?.validate() + viewType()?.validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + internal fun validity(): Int = + (if (objectId.asKnown() == null) 0 else 1) + + (objectType.asKnown()?.validity() ?: 0) + + (if (name.asKnown() == null) 0 else 1) + + (options.asKnown()?.validity() ?: 0) + + (if (userId.asKnown() == null) 0 else 1) + + (viewData.asKnown()?.validity() ?: 0) + + (viewType.asKnown()?.validity() ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is ViewType && this.value == other.value + return other is Body && + objectId == other.objectId && + objectType == other.objectType && + name == other.name && + options == other.options && + userId == other.userId && + viewData == other.viewData && + viewType == other.viewType && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() + private val hashCode: Int by lazy { + Objects.hash( + objectId, + objectType, + name, + options, + userId, + viewData, + viewType, + additionalProperties, + ) + } - override fun toString() = value.toString() + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{objectId=$objectId, objectType=$objectType, name=$name, options=$options, userId=$userId, viewData=$viewData, viewType=$viewType, additionalProperties=$additionalProperties}" + } + + /** Type of table that the view corresponds to. */ + class ViewType @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 { - val PROJECTS = ViewType(JsonField.of("projects")) + val PROJECTS = of("projects") + + val EXPERIMENTS = of("experiments") + + val EXPERIMENT = of("experiment") + + val PLAYGROUNDS = of("playgrounds") - val LOGS = ViewType(JsonField.of("logs")) + val PLAYGROUND = of("playground") - val EXPERIMENTS = ViewType(JsonField.of("experiments")) + val DATASETS = of("datasets") - val DATASETS = ViewType(JsonField.of("datasets")) + val DATASET = of("dataset") - val PROMPTS = ViewType(JsonField.of("prompts")) + val PROMPTS = of("prompts") - val PLAYGROUNDS = ViewType(JsonField.of("playgrounds")) + val TOOLS = of("tools") - val EXPERIMENT = ViewType(JsonField.of("experiment")) + val SCORERS = of("scorers") - val DATASET = ViewType(JsonField.of("dataset")) + val LOGS = of("logs") fun of(value: String) = ViewType(JsonField.of(value)) } + /** An enum containing [ViewType]'s known values. */ enum class Known { PROJECTS, - LOGS, EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, + PROMPTS, + TOOLS, + SCORERS, + LOGS, } + /** + * An enum containing [ViewType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ViewType] 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 { PROJECTS, - LOGS, EXPERIMENTS, - DATASETS, - PROMPTS, - PLAYGROUNDS, EXPERIMENT, + PLAYGROUNDS, + PLAYGROUND, + DATASETS, DATASET, + PROMPTS, + TOOLS, + SCORERS, + LOGS, + /** An enum member indicating that [ViewType] 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) { PROJECTS -> Value.PROJECTS - LOGS -> Value.LOGS EXPERIMENTS -> Value.EXPERIMENTS - DATASETS -> Value.DATASETS - PROMPTS -> Value.PROMPTS - PLAYGROUNDS -> Value.PLAYGROUNDS EXPERIMENT -> Value.EXPERIMENT + PLAYGROUNDS -> Value.PLAYGROUNDS + PLAYGROUND -> Value.PLAYGROUND + DATASETS -> Value.DATASETS DATASET -> Value.DATASET + PROMPTS -> Value.PROMPTS + TOOLS -> Value.TOOLS + SCORERS -> Value.SCORERS + LOGS -> Value.LOGS 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 BraintrustInvalidDataException if this class instance's value is a not a known + * member. + */ fun known(): Known = when (this) { PROJECTS -> Known.PROJECTS - LOGS -> Known.LOGS EXPERIMENTS -> Known.EXPERIMENTS - DATASETS -> Known.DATASETS - PROMPTS -> Known.PROMPTS - PLAYGROUNDS -> Known.PLAYGROUNDS EXPERIMENT -> Known.EXPERIMENT + PLAYGROUNDS -> Known.PLAYGROUNDS + PLAYGROUND -> Known.PLAYGROUND + DATASETS -> Known.DATASETS DATASET -> Known.DATASET + PROMPTS -> Known.PROMPTS + TOOLS -> Known.TOOLS + SCORERS -> Known.SCORERS + LOGS -> Known.LOGS else -> throw BraintrustInvalidDataException("Unknown ViewType: $value") } - fun asString(): String = _value().asStringOrThrow() + /** + * 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 BraintrustInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString() ?: throw BraintrustInvalidDataException("Value is not a String") + + private var validated: Boolean = false + + fun validate(): ViewType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: BraintrustInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + 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 ViewType && 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 ViewUpdateParams && + viewId == other.viewId && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams } + + override fun hashCode(): Int = + Objects.hash(viewId, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ViewUpdateParams{viewId=$viewId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/Handlers.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/Handlers.kt deleted file mode 100755 index baa64dff..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/Handlers.kt +++ /dev/null @@ -1,182 +0,0 @@ -@file:JvmName("Handlers") - -package com.braintrustdata.api.services - -import com.braintrustdata.api.core.http.BinaryResponseContent -import com.braintrustdata.api.core.http.HttpResponse -import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BadRequestException -import com.braintrustdata.api.errors.BraintrustError -import com.braintrustdata.api.errors.BraintrustException -import com.braintrustdata.api.errors.InternalServerException -import com.braintrustdata.api.errors.NotFoundException -import com.braintrustdata.api.errors.PermissionDeniedException -import com.braintrustdata.api.errors.RateLimitException -import com.braintrustdata.api.errors.UnauthorizedException -import com.braintrustdata.api.errors.UnexpectedStatusCodeException -import com.braintrustdata.api.errors.UnprocessableEntityException -import com.fasterxml.jackson.databind.json.JsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.google.common.collect.ListMultimap -import java.io.ByteArrayInputStream -import java.io.InputStream -import java.io.OutputStream - -internal fun emptyHandler(): Handler = EmptyHandler - -private object EmptyHandler : Handler { - override fun handle(response: HttpResponse): Void? = null -} - -internal fun stringHandler(): Handler = StringHandler - -internal fun binaryHandler(): Handler = BinaryHandler - -private object StringHandler : Handler { - override fun handle(response: HttpResponse): String { - return response.body().readBytes().toString(Charsets.UTF_8) - } -} - -private object BinaryHandler : Handler { - override fun handle(response: HttpResponse): BinaryResponseContent { - return object : BinaryResponseContent { - override fun contentType(): String? = - response.headers().get("Content-Type").firstOrNull() - - override fun body(): InputStream = response.body() - - override fun close() = response.close() - - override fun writeTo(outputStream: OutputStream) { - response.body().copyTo(outputStream) - } - } - } -} - -internal inline fun jsonHandler(jsonMapper: JsonMapper): Handler { - return object : Handler { - override fun handle(response: HttpResponse): T { - try { - return jsonMapper.readValue(response.body(), jacksonTypeRef()) - } catch (e: Exception) { - throw BraintrustException("Error reading response", e) - } - } - } -} - -internal fun errorHandler(jsonMapper: JsonMapper): Handler { - val handler = jsonHandler(jsonMapper) - - return object : Handler { - override fun handle(response: HttpResponse): BraintrustError { - try { - return handler.handle(response) - } catch (e: Exception) { - return BraintrustError.builder().build() - } - } - } -} - -internal fun Handler.withErrorHandler(errorHandler: Handler): Handler { - return object : Handler { - override fun handle(response: HttpResponse): T { - when (val statusCode = response.statusCode()) { - in 200..299 -> { - return this@withErrorHandler.handle(response) - } - 400 -> { - val buffered = response.buffered() - throw BadRequestException( - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - 401 -> { - val buffered = response.buffered() - throw UnauthorizedException( - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - 403 -> { - val buffered = response.buffered() - throw PermissionDeniedException( - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - 404 -> { - val buffered = response.buffered() - throw NotFoundException( - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - 422 -> { - val buffered = response.buffered() - throw UnprocessableEntityException( - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - 429 -> { - val buffered = response.buffered() - throw RateLimitException( - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - in 500..599 -> { - val buffered = response.buffered() - throw InternalServerException( - statusCode, - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - else -> { - val buffered = response.buffered() - throw UnexpectedStatusCodeException( - statusCode, - buffered.headers(), - StringHandler.handle(buffered), - errorHandler.handle(buffered), - ) - } - } - } - } -} - -private fun HttpResponse.buffered(): HttpResponse { - val body = body().readBytes() - - return object : HttpResponse { - override fun statusCode(): Int { - return this@buffered.statusCode() - } - - override fun headers(): ListMultimap { - return this@buffered.headers() - } - - override fun body(): InputStream { - return ByteArrayInputStream(body) - } - - override fun close() { - this@buffered.close() - } - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/HttpRequestBodies.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/HttpRequestBodies.kt deleted file mode 100755 index 768934d9..00000000 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/HttpRequestBodies.kt +++ /dev/null @@ -1,112 +0,0 @@ -@file:JvmName("HttpRequestBodies") - -package com.braintrustdata.api.services - -import com.braintrustdata.api.core.Enum -import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.MultipartFormValue -import com.braintrustdata.api.core.http.HttpRequestBody -import com.braintrustdata.api.errors.BraintrustException -import com.fasterxml.jackson.databind.json.JsonMapper -import java.io.ByteArrayOutputStream -import java.io.OutputStream -import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder - -internal inline fun json( - jsonMapper: JsonMapper, - value: T, -): HttpRequestBody { - return object : HttpRequestBody { - private var cachedBytes: ByteArray? = null - - private fun serialize(): ByteArray { - if (cachedBytes != null) return cachedBytes!! - - val buffer = ByteArrayOutputStream() - try { - jsonMapper.writeValue(buffer, value) - cachedBytes = buffer.toByteArray() - return cachedBytes!! - } catch (e: Exception) { - throw BraintrustException("Error writing request", e) - } - } - - override fun writeTo(outputStream: OutputStream) { - outputStream.write(serialize()) - } - - override fun contentType(): String = "application/json" - - override fun contentLength(): Long { - return serialize().size.toLong() - } - - override fun repeatable(): Boolean = true - - override fun close() {} - } -} - -internal fun multipartFormData( - jsonMapper: JsonMapper, - parts: Array?> -): HttpRequestBody { - val builder = MultipartEntityBuilder.create() - parts.forEach { part -> - if (part?.value != null) { - when (part.value) { - is JsonValue -> { - val buffer = ByteArrayOutputStream() - try { - jsonMapper.writeValue(buffer, part.value) - } catch (e: Exception) { - throw BraintrustException("Error serializing value to json", e) - } - builder.addBinaryBody( - part.name, - buffer.toByteArray(), - part.contentType, - part.filename - ) - } - is Boolean -> - builder.addTextBody( - part.name, - if (part.value) "true" else "false", - part.contentType - ) - is Int -> builder.addTextBody(part.name, part.value.toString(), part.contentType) - is Long -> builder.addTextBody(part.name, part.value.toString(), part.contentType) - is Double -> builder.addTextBody(part.name, part.value.toString(), part.contentType) - is ByteArray -> - builder.addBinaryBody(part.name, part.value, part.contentType, part.filename) - is String -> builder.addTextBody(part.name, part.value, part.contentType) - is Enum -> builder.addTextBody(part.name, part.value.toString(), part.contentType) - else -> - throw IllegalArgumentException( - "Unsupported content type: ${part.value::class.java.simpleName}" - ) - } - } - } - val entity = builder.build() - - return object : HttpRequestBody { - override fun writeTo(outputStream: OutputStream) { - try { - return entity.writeTo(outputStream) - } catch (e: Exception) { - throw BraintrustException("Error writing request", e) - } - } - - override fun contentType(): String = entity.contentType - - override fun contentLength(): Long = -1 - - override fun repeatable(): Boolean = entity.isRepeatable - - override fun close() = entity.close() - } -} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsync.kt index e073e375..26aed6e7 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Acl import com.braintrustdata.api.models.AclBatchUpdateParams import com.braintrustdata.api.models.AclBatchUpdateResponse @@ -14,51 +14,194 @@ import com.braintrustdata.api.models.AclFindAndDeleteParams import com.braintrustdata.api.models.AclListPageAsync import com.braintrustdata.api.models.AclListParams import com.braintrustdata.api.models.AclRetrieveParams +import com.google.errorprone.annotations.MustBeClosed interface AclServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): AclServiceAsync + /** * Create a new acl. If there is an existing acl with the same contents as the one specified in * the request, will return the existing acl unmodified */ suspend fun create( params: AclCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Acl /** Get an acl object by its id */ + suspend fun retrieve( + aclId: String, + params: AclRetrieveParams = AclRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Acl = retrieve(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: AclRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Acl + /** @see retrieve */ + suspend fun retrieve(aclId: String, requestOptions: RequestOptions): Acl = + retrieve(aclId, AclRetrieveParams.none(), requestOptions) + /** * List out all acls. The acls are sorted by creation date, with the most recently-created acls * coming first */ suspend fun list( params: AclListParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AclListPageAsync /** Delete an acl object by its id */ + suspend fun delete( + aclId: String, + params: AclDeleteParams = AclDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Acl = delete(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: AclDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Acl + /** @see delete */ + suspend fun delete(aclId: String, requestOptions: RequestOptions): Acl = + delete(aclId, AclDeleteParams.none(), requestOptions) + /** * Batch update acls. This operation is idempotent, so adding acls which already exist will have * no effect, and removing acls which do not exist will have no effect. */ suspend fun batchUpdate( - params: AclBatchUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + params: AclBatchUpdateParams = AclBatchUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): AclBatchUpdateResponse + /** @see batchUpdate */ + suspend fun batchUpdate(requestOptions: RequestOptions): AclBatchUpdateResponse = + batchUpdate(AclBatchUpdateParams.none(), requestOptions) + /** Delete a single acl */ suspend fun findAndDelete( params: AclFindAndDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Acl + + /** A view of [AclServiceAsync] 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: (ClientOptions.Builder) -> Unit): AclServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/acl`, but is otherwise the same as + * [AclServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: AclCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/acl/{acl_id}`, but is otherwise the same as + * [AclServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + aclId: String, + params: AclRetrieveParams = AclRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = retrieve(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: AclRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve(aclId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(aclId, AclRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/acl`, but is otherwise the same as + * [AclServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: AclListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `delete /v1/acl/{acl_id}`, but is otherwise the same as + * [AclServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + aclId: String, + params: AclDeleteParams = AclDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = delete(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: AclDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete(aclId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(aclId, AclDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/acl/batch_update`, but is otherwise the same as + * [AclServiceAsync.batchUpdate]. + */ + @MustBeClosed + suspend fun batchUpdate( + params: AclBatchUpdateParams = AclBatchUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see batchUpdate */ + @MustBeClosed + suspend fun batchUpdate( + requestOptions: RequestOptions + ): HttpResponseFor = + batchUpdate(AclBatchUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/acl`, but is otherwise the same as + * [AclServiceAsync.findAndDelete]. + */ + @MustBeClosed + suspend fun findAndDelete( + params: AclFindAndDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsyncImpl.kt index 19cfd93f..37ea8203 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AclServiceAsyncImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Acl import com.braintrustdata.api.models.AclBatchUpdateParams import com.braintrustdata.api.models.AclBatchUpdateResponse @@ -15,191 +23,241 @@ import com.braintrustdata.api.models.AclCreateParams import com.braintrustdata.api.models.AclDeleteParams import com.braintrustdata.api.models.AclFindAndDeleteParams import com.braintrustdata.api.models.AclListPageAsync +import com.braintrustdata.api.models.AclListPageResponse import com.braintrustdata.api.models.AclListParams import com.braintrustdata.api.models.AclRetrieveParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class AclServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : AclServiceAsync { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new acl. If there is an existing acl with the same contents as the one specified in - * the request, will return the existing acl unmodified - */ - override suspend fun create(params: AclCreateParams, requestOptions: RequestOptions): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "acl") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + +class AclServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + AclServiceAsync { + + private val withRawResponse: AclServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): AclServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): AclServiceAsync = + AclServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + + override suspend fun create(params: AclCreateParams, requestOptions: RequestOptions): Acl = + // post /v1/acl + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve(params: AclRetrieveParams, requestOptions: RequestOptions): Acl = + // get /v1/acl/{acl_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun list( + params: AclListParams, + requestOptions: RequestOptions, + ): AclListPageAsync = + // get /v1/acl + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete(params: AclDeleteParams, requestOptions: RequestOptions): Acl = + // delete /v1/acl/{acl_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun batchUpdate( + params: AclBatchUpdateParams, + requestOptions: RequestOptions, + ): AclBatchUpdateResponse = + // post /v1/acl/batch_update + withRawResponse().batchUpdate(params, requestOptions).parse() + + override suspend fun findAndDelete( + params: AclFindAndDeleteParams, + requestOptions: RequestOptions, + ): Acl = + // delete /v1/acl + withRawResponse().findAndDelete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AclServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): AclServiceAsync.WithRawResponse = + AclServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: AclCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get an acl object by its id */ - override suspend fun retrieve(params: AclRetrieveParams, requestOptions: RequestOptions): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "acl", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: AclRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aclId", params.aclId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all acls. The acls are sorted by creation date, with the most recently-created acls - * coming first - */ - override suspend fun list( - params: AclListParams, - requestOptions: RequestOptions - ): AclListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "acl") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: AclListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { AclListPageAsync.of(this, params, it) } + .let { + AclListPageAsync.builder() + .service(AclServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete an acl object by its id */ - override suspend fun delete(params: AclDeleteParams, requestOptions: RequestOptions): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "acl", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun delete( + params: AclDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aclId", params.aclId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val batchUpdateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val batchUpdateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Batch update acls. This operation is idempotent, so adding acls which already exist will have - * no effect, and removing acls which do not exist will have no effect. - */ - override suspend fun batchUpdate( - params: AclBatchUpdateParams, - requestOptions: RequestOptions - ): AclBatchUpdateResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "acl", "batch-update") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { batchUpdateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun batchUpdate( + params: AclBatchUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl", "batch_update") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { batchUpdateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val findAndDeleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val findAndDeleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Delete a single acl */ - override suspend fun findAndDelete( - params: AclFindAndDeleteParams, - requestOptions: RequestOptions - ): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "acl") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { findAndDeleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun findAndDelete( + params: AclFindAndDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { findAndDeleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsync.kt index c5ffeab9..5b6af051 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.AISecret import com.braintrustdata.api.models.AiSecretCreateParams import com.braintrustdata.api.models.AiSecretDeleteParams @@ -14,53 +14,103 @@ import com.braintrustdata.api.models.AiSecretListParams import com.braintrustdata.api.models.AiSecretReplaceParams import com.braintrustdata.api.models.AiSecretRetrieveParams import com.braintrustdata.api.models.AiSecretUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface AiSecretServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): AiSecretServiceAsync + /** * Create a new ai_secret. If there is an existing ai_secret with the same name as the one * specified in the request, will return the existing ai_secret unmodified */ suspend fun create( params: AiSecretCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret /** Get an ai_secret object by its id */ + suspend fun retrieve( + aiSecretId: String, + params: AiSecretRetrieveParams = AiSecretRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AISecret = retrieve(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: AiSecretRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + /** @see retrieve */ + suspend fun retrieve(aiSecretId: String, requestOptions: RequestOptions): AISecret = + retrieve(aiSecretId, AiSecretRetrieveParams.none(), requestOptions) + /** * Partially update an ai_secret object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + aiSecretId: String, + params: AiSecretUpdateParams = AiSecretUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AISecret = update(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see update */ suspend fun update( params: AiSecretUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + /** @see update */ + suspend fun update(aiSecretId: String, requestOptions: RequestOptions): AISecret = + update(aiSecretId, AiSecretUpdateParams.none(), requestOptions) + /** * List out all ai_secrets. The ai_secrets are sorted by creation date, with the most * recently-created ai_secrets coming first */ suspend fun list( - params: AiSecretListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: AiSecretListParams = AiSecretListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): AiSecretListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): AiSecretListPageAsync = + list(AiSecretListParams.none(), requestOptions) + /** Delete an ai_secret object by its id */ + suspend fun delete( + aiSecretId: String, + params: AiSecretDeleteParams = AiSecretDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AISecret = delete(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: AiSecretDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + /** @see delete */ + suspend fun delete(aiSecretId: String, requestOptions: RequestOptions): AISecret = + delete(aiSecretId, AiSecretDeleteParams.none(), requestOptions) + /** Delete a single ai_secret */ suspend fun findAndDelete( params: AiSecretFindAndDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret /** @@ -69,6 +119,147 @@ interface AiSecretServiceAsync { */ suspend fun replace( params: AiSecretReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + + /** + * A view of [AiSecretServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): AiSecretServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/ai_secret`, but is otherwise the same as + * [AiSecretServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: AiSecretCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/ai_secret/{ai_secret_id}`, but is otherwise the + * same as [AiSecretServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + aiSecretId: String, + params: AiSecretRetrieveParams = AiSecretRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: AiSecretRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + aiSecretId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(aiSecretId, AiSecretRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/ai_secret/{ai_secret_id}`, but is otherwise + * the same as [AiSecretServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + aiSecretId: String, + params: AiSecretUpdateParams = AiSecretUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: AiSecretUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + aiSecretId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(aiSecretId, AiSecretUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/ai_secret`, but is otherwise the same as + * [AiSecretServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: AiSecretListParams = AiSecretListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(AiSecretListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/ai_secret/{ai_secret_id}`, but is otherwise + * the same as [AiSecretServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + aiSecretId: String, + params: AiSecretDeleteParams = AiSecretDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: AiSecretDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + aiSecretId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(aiSecretId, AiSecretDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/ai_secret`, but is otherwise the same as + * [AiSecretServiceAsync.findAndDelete]. + */ + @MustBeClosed + suspend fun findAndDelete( + params: AiSecretFindAndDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `put /v1/ai_secret`, but is otherwise the same as + * [AiSecretServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: AiSecretReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsyncImpl.kt index de0af9d3..58572b21 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsyncImpl.kt @@ -4,244 +4,311 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.AISecret import com.braintrustdata.api.models.AiSecretCreateParams import com.braintrustdata.api.models.AiSecretDeleteParams import com.braintrustdata.api.models.AiSecretFindAndDeleteParams import com.braintrustdata.api.models.AiSecretListPageAsync +import com.braintrustdata.api.models.AiSecretListPageResponse import com.braintrustdata.api.models.AiSecretListParams import com.braintrustdata.api.models.AiSecretReplaceParams import com.braintrustdata.api.models.AiSecretRetrieveParams import com.braintrustdata.api.models.AiSecretUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class AiSecretServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : AiSecretServiceAsync { +class AiSecretServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + AiSecretServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: AiSecretServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): AiSecretServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): AiSecretServiceAsync = + AiSecretServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new ai_secret. If there is an existing ai_secret with the same name as the one - * specified in the request, will return the existing ai_secret unmodified - */ override suspend fun create( params: AiSecretCreateParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): AISecret = + // post /v1/ai_secret + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: AiSecretRetrieveParams, + requestOptions: RequestOptions, + ): AISecret = + // get /v1/ai_secret/{ai_secret_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: AiSecretUpdateParams, + requestOptions: RequestOptions, + ): AISecret = + // patch /v1/ai_secret/{ai_secret_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: AiSecretListParams, + requestOptions: RequestOptions, + ): AiSecretListPageAsync = + // get /v1/ai_secret + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: AiSecretDeleteParams, + requestOptions: RequestOptions, + ): AISecret = + // delete /v1/ai_secret/{ai_secret_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun findAndDelete( + params: AiSecretFindAndDeleteParams, + requestOptions: RequestOptions, + ): AISecret = + // delete /v1/ai_secret + withRawResponse().findAndDelete(params, requestOptions).parse() + + override suspend fun replace( + params: AiSecretReplaceParams, + requestOptions: RequestOptions, + ): AISecret = + // put /v1/ai_secret + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AiSecretServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): AiSecretServiceAsync.WithRawResponse = + AiSecretServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: AiSecretCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get an ai_secret object by its id */ - override suspend fun retrieve( - params: AiSecretRetrieveParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "ai_secret", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: AiSecretRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aiSecretId", params.aiSecretId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update an ai_secret object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: AiSecretUpdateParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "ai_secret", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: AiSecretUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aiSecretId", params.aiSecretId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all ai_secrets. The ai_secrets are sorted by creation date, with the most - * recently-created ai_secrets coming first - */ - override suspend fun list( - params: AiSecretListParams, - requestOptions: RequestOptions - ): AiSecretListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: AiSecretListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + AiSecretListPageAsync.builder() + .service(AiSecretServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { AiSecretListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete an ai_secret object by its id */ - override suspend fun delete( - params: AiSecretDeleteParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "ai_secret", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: AiSecretDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aiSecretId", params.aiSecretId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val findAndDeleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val findAndDeleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete a single ai_secret */ - override suspend fun findAndDelete( - params: AiSecretFindAndDeleteParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { findAndDeleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun findAndDelete( + params: AiSecretFindAndDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { findAndDeleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace ai_secret. If there is an existing ai_secret with the same name as the one - * specified in the request, will replace the existing ai_secret with the provided fields - */ - override suspend fun replace( - params: AiSecretReplaceParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun replace( + params: AiSecretReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsync.kt index c2b31587..b1927af3 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.ApiKey import com.braintrustdata.api.models.ApiKeyCreateParams import com.braintrustdata.api.models.ApiKeyDeleteParams @@ -12,36 +12,167 @@ import com.braintrustdata.api.models.ApiKeyListPageAsync import com.braintrustdata.api.models.ApiKeyListParams import com.braintrustdata.api.models.ApiKeyRetrieveParams import com.braintrustdata.api.models.CreateApiKeyOutput +import com.google.errorprone.annotations.MustBeClosed interface ApiKeyServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): ApiKeyServiceAsync + /** * Create a new api_key. It is possible to have multiple API keys with the same name. There is * no de-duplication */ suspend fun create( params: ApiKeyCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): CreateApiKeyOutput /** Get an api_key object by its id */ + suspend fun retrieve( + apiKeyId: String, + params: ApiKeyRetrieveParams = ApiKeyRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ApiKey = retrieve(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: ApiKeyRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ApiKey + /** @see retrieve */ + suspend fun retrieve(apiKeyId: String, requestOptions: RequestOptions): ApiKey = + retrieve(apiKeyId, ApiKeyRetrieveParams.none(), requestOptions) + /** * List out all api_keys. The api_keys are sorted by creation date, with the most * recently-created api_keys coming first */ suspend fun list( - params: ApiKeyListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ApiKeyListParams = ApiKeyListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ApiKeyListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): ApiKeyListPageAsync = + list(ApiKeyListParams.none(), requestOptions) + /** Delete an api_key object by its id */ + suspend fun delete( + apiKeyId: String, + params: ApiKeyDeleteParams = ApiKeyDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ApiKey = delete(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: ApiKeyDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ApiKey + + /** @see delete */ + suspend fun delete(apiKeyId: String, requestOptions: RequestOptions): ApiKey = + delete(apiKeyId, ApiKeyDeleteParams.none(), requestOptions) + + /** + * A view of [ApiKeyServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): ApiKeyServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/api_key`, but is otherwise the same as + * [ApiKeyServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: ApiKeyCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/api_key/{api_key_id}`, but is otherwise the same + * as [ApiKeyServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + apiKeyId: String, + params: ApiKeyRetrieveParams = ApiKeyRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: ApiKeyRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + apiKeyId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = retrieve(apiKeyId, ApiKeyRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/api_key`, but is otherwise the same as + * [ApiKeyServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: ApiKeyListParams = ApiKeyListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ApiKeyListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/api_key/{api_key_id}`, but is otherwise the + * same as [ApiKeyServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + apiKeyId: String, + params: ApiKeyDeleteParams = ApiKeyDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: ApiKeyDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + apiKeyId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = delete(apiKeyId, ApiKeyDeleteParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsyncImpl.kt index a7d2dd58..0c2907da 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsyncImpl.kt @@ -4,148 +4,199 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.ApiKey import com.braintrustdata.api.models.ApiKeyCreateParams import com.braintrustdata.api.models.ApiKeyDeleteParams import com.braintrustdata.api.models.ApiKeyListPageAsync +import com.braintrustdata.api.models.ApiKeyListPageResponse import com.braintrustdata.api.models.ApiKeyListParams import com.braintrustdata.api.models.ApiKeyRetrieveParams import com.braintrustdata.api.models.CreateApiKeyOutput -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ApiKeyServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : ApiKeyServiceAsync { +class ApiKeyServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + ApiKeyServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ApiKeyServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ApiKeyServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ApiKeyServiceAsync = + ApiKeyServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new api_key. It is possible to have multiple API keys with the same name. There is - * no de-duplication - */ override suspend fun create( params: ApiKeyCreateParams, - requestOptions: RequestOptions - ): CreateApiKeyOutput { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "api_key") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): CreateApiKeyOutput = + // post /v1/api_key + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: ApiKeyRetrieveParams, + requestOptions: RequestOptions, + ): ApiKey = + // get /v1/api_key/{api_key_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun list( + params: ApiKeyListParams, + requestOptions: RequestOptions, + ): ApiKeyListPageAsync = + // get /v1/api_key + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: ApiKeyDeleteParams, + requestOptions: RequestOptions, + ): ApiKey = + // delete /v1/api_key/{api_key_id} + withRawResponse().delete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ApiKeyServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ApiKeyServiceAsync.WithRawResponse = + ApiKeyServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: ApiKeyCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Get an api_key object by its id */ - override suspend fun retrieve( - params: ApiKeyRetrieveParams, - requestOptions: RequestOptions - ): ApiKey { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "api_key", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: ApiKeyRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("apiKeyId", params.apiKeyId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all api_keys. The api_keys are sorted by creation date, with the most - * recently-created api_keys coming first - */ - override suspend fun list( - params: ApiKeyListParams, - requestOptions: RequestOptions - ): ApiKeyListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "api_key") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: ApiKeyListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + ApiKeyListPageAsync.builder() + .service(ApiKeyServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { ApiKeyListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Delete an api_key object by its id */ - override suspend fun delete( - params: ApiKeyDeleteParams, - requestOptions: RequestOptions - ): ApiKey { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "api_key", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: ApiKeyDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("apiKeyId", params.apiKeyId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsync.kt index d90700a3..d0fe6173 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Dataset import com.braintrustdata.api.models.DatasetCreateParams import com.braintrustdata.api.models.DatasetDeleteParams @@ -21,82 +21,432 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchDatasetEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeDatasetResponse +import com.google.errorprone.annotations.MustBeClosed interface DatasetServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): DatasetServiceAsync + /** * Create a new dataset. If there is an existing dataset in the project with the same name as * the one specified in the request, will return the existing dataset unmodified */ suspend fun create( params: DatasetCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset /** Get a dataset object by its id */ + suspend fun retrieve( + datasetId: String, + params: DatasetRetrieveParams = DatasetRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Dataset = retrieve(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: DatasetRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset + /** @see retrieve */ + suspend fun retrieve(datasetId: String, requestOptions: RequestOptions): Dataset = + retrieve(datasetId, DatasetRetrieveParams.none(), requestOptions) + /** * Partially update a dataset object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + datasetId: String, + params: DatasetUpdateParams = DatasetUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Dataset = update(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see update */ suspend fun update( params: DatasetUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset + /** @see update */ + suspend fun update(datasetId: String, requestOptions: RequestOptions): Dataset = + update(datasetId, DatasetUpdateParams.none(), requestOptions) + /** * List out all datasets. The datasets are sorted by creation date, with the most * recently-created datasets coming first */ suspend fun list( - params: DatasetListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: DatasetListParams = DatasetListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): DatasetListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): DatasetListPageAsync = + list(DatasetListParams.none(), requestOptions) + /** Delete a dataset object by its id */ + suspend fun delete( + datasetId: String, + params: DatasetDeleteParams = DatasetDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Dataset = delete(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: DatasetDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset + /** @see delete */ + suspend fun delete(datasetId: String, requestOptions: RequestOptions): Dataset = + delete(datasetId, DatasetDeleteParams.none(), requestOptions) + /** Log feedback for a set of dataset events */ + suspend fun feedback( + datasetId: String, + params: DatasetFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FeedbackResponseSchema = + feedback(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see feedback */ suspend fun feedback( params: DatasetFeedbackParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FeedbackResponseSchema /** * Fetch the events in a dataset. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body + * parameters in the URL query rather than in the request body. For more complex queries, use + * the `POST /btql` endpoint. */ + suspend fun fetch( + datasetId: String, + params: DatasetFetchParams = DatasetFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchDatasetEventsResponse = + fetch(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetch */ suspend fun fetch( params: DatasetFetchParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchDatasetEventsResponse + /** @see fetch */ + suspend fun fetch( + datasetId: String, + requestOptions: RequestOptions, + ): FetchDatasetEventsResponse = fetch(datasetId, DatasetFetchParams.none(), requestOptions) + /** * Fetch the events in a dataset. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query + * parameters in the request body rather than in the URL query. For more complex queries, use + * the `POST /btql` endpoint. */ + suspend fun fetchPost( + datasetId: String, + params: DatasetFetchPostParams = DatasetFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchDatasetEventsResponse = + fetchPost(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetchPost */ suspend fun fetchPost( params: DatasetFetchPostParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchDatasetEventsResponse + /** @see fetchPost */ + suspend fun fetchPost( + datasetId: String, + requestOptions: RequestOptions, + ): FetchDatasetEventsResponse = + fetchPost(datasetId, DatasetFetchPostParams.none(), requestOptions) + /** Insert a set of events into the dataset */ suspend fun insert( + datasetId: String, params: DatasetInsertParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): InsertEventsResponse = + insert(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see insert */ + suspend fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), ): InsertEventsResponse /** Summarize dataset */ + suspend fun summarize( + datasetId: String, + params: DatasetSummarizeParams = DatasetSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SummarizeDatasetResponse = + summarize(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see summarize */ suspend fun summarize( params: DatasetSummarizeParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): SummarizeDatasetResponse + + /** @see summarize */ + suspend fun summarize( + datasetId: String, + requestOptions: RequestOptions, + ): SummarizeDatasetResponse = + summarize(datasetId, DatasetSummarizeParams.none(), requestOptions) + + /** + * A view of [DatasetServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): DatasetServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/dataset`, but is otherwise the same as + * [DatasetServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: DatasetCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/dataset/{dataset_id}`, but is otherwise the same + * as [DatasetServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + datasetId: String, + params: DatasetRetrieveParams = DatasetRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: DatasetRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(datasetId, DatasetRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/dataset/{dataset_id}`, but is otherwise the + * same as [DatasetServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + datasetId: String, + params: DatasetUpdateParams = DatasetUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: DatasetUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = update(datasetId, DatasetUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/dataset`, but is otherwise the same as + * [DatasetServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: DatasetListParams = DatasetListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(DatasetListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/dataset/{dataset_id}`, but is otherwise the + * same as [DatasetServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + datasetId: String, + params: DatasetDeleteParams = DatasetDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: DatasetDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = delete(datasetId, DatasetDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/dataset/{dataset_id}/feedback`, but is + * otherwise the same as [DatasetServiceAsync.feedback]. + */ + @MustBeClosed + suspend fun feedback( + datasetId: String, + params: DatasetFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + feedback(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see feedback */ + @MustBeClosed + suspend fun feedback( + params: DatasetFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/dataset/{dataset_id}/fetch`, but is otherwise + * the same as [DatasetServiceAsync.fetch]. + */ + @MustBeClosed + suspend fun fetch( + datasetId: String, + params: DatasetFetchParams = DatasetFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetch(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetch */ + @MustBeClosed + suspend fun fetch( + params: DatasetFetchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetch */ + @MustBeClosed + suspend fun fetch( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetch(datasetId, DatasetFetchParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/dataset/{dataset_id}/fetch`, but is otherwise + * the same as [DatasetServiceAsync.fetchPost]. + */ + @MustBeClosed + suspend fun fetchPost( + datasetId: String, + params: DatasetFetchPostParams = DatasetFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetchPost(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetchPost */ + @MustBeClosed + suspend fun fetchPost( + params: DatasetFetchPostParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetchPost */ + @MustBeClosed + suspend fun fetchPost( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetchPost(datasetId, DatasetFetchPostParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/dataset/{dataset_id}/insert`, but is otherwise + * the same as [DatasetServiceAsync.insert]. + */ + @MustBeClosed + suspend fun insert( + datasetId: String, + params: DatasetInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + insert(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see insert */ + @MustBeClosed + suspend fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/dataset/{dataset_id}/summarize`, but is + * otherwise the same as [DatasetServiceAsync.summarize]. + */ + @MustBeClosed + suspend fun summarize( + datasetId: String, + params: DatasetSummarizeParams = DatasetSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + summarize(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see summarize */ + @MustBeClosed + suspend fun summarize( + params: DatasetSummarizeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see summarize */ + @MustBeClosed + suspend fun summarize( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + summarize(datasetId, DatasetSummarizeParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsyncImpl.kt index ab361d04..cd774d91 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsyncImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Dataset import com.braintrustdata.api.models.DatasetCreateParams import com.braintrustdata.api.models.DatasetDeleteParams @@ -16,6 +24,7 @@ import com.braintrustdata.api.models.DatasetFetchParams import com.braintrustdata.api.models.DatasetFetchPostParams import com.braintrustdata.api.models.DatasetInsertParams import com.braintrustdata.api.models.DatasetListPageAsync +import com.braintrustdata.api.models.DatasetListPageResponse import com.braintrustdata.api.models.DatasetListParams import com.braintrustdata.api.models.DatasetRetrieveParams import com.braintrustdata.api.models.DatasetSummarizeParams @@ -24,322 +33,404 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchDatasetEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeDatasetResponse -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class DatasetServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : DatasetServiceAsync { +class DatasetServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + DatasetServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: DatasetServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): DatasetServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): DatasetServiceAsync = + DatasetServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new dataset. If there is an existing dataset in the project with the same name as - * the one specified in the request, will return the existing dataset unmodified - */ override suspend fun create( params: DatasetCreateParams, - requestOptions: RequestOptions - ): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Dataset = + // post /v1/dataset + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: DatasetRetrieveParams, + requestOptions: RequestOptions, + ): Dataset = + // get /v1/dataset/{dataset_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: DatasetUpdateParams, + requestOptions: RequestOptions, + ): Dataset = + // patch /v1/dataset/{dataset_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: DatasetListParams, + requestOptions: RequestOptions, + ): DatasetListPageAsync = + // get /v1/dataset + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: DatasetDeleteParams, + requestOptions: RequestOptions, + ): Dataset = + // delete /v1/dataset/{dataset_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun feedback( + params: DatasetFeedbackParams, + requestOptions: RequestOptions, + ): FeedbackResponseSchema = + // post /v1/dataset/{dataset_id}/feedback + withRawResponse().feedback(params, requestOptions).parse() + + override suspend fun fetch( + params: DatasetFetchParams, + requestOptions: RequestOptions, + ): FetchDatasetEventsResponse = + // get /v1/dataset/{dataset_id}/fetch + withRawResponse().fetch(params, requestOptions).parse() + + override suspend fun fetchPost( + params: DatasetFetchPostParams, + requestOptions: RequestOptions, + ): FetchDatasetEventsResponse = + // post /v1/dataset/{dataset_id}/fetch + withRawResponse().fetchPost(params, requestOptions).parse() + + override suspend fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions, + ): InsertEventsResponse = + // post /v1/dataset/{dataset_id}/insert + withRawResponse().insert(params, requestOptions).parse() + + override suspend fun summarize( + params: DatasetSummarizeParams, + requestOptions: RequestOptions, + ): SummarizeDatasetResponse = + // get /v1/dataset/{dataset_id}/summarize + withRawResponse().summarize(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + DatasetServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): DatasetServiceAsync.WithRawResponse = + DatasetServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: DatasetCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get a dataset object by its id */ - override suspend fun retrieve( - params: DatasetRetrieveParams, - requestOptions: RequestOptions - ): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: DatasetRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * Partially update a dataset object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: DatasetUpdateParams, - requestOptions: RequestOptions - ): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "dataset", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: DatasetUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all datasets. The datasets are sorted by creation date, with the most - * recently-created datasets coming first - */ - override suspend fun list( - params: DatasetListParams, - requestOptions: RequestOptions - ): DatasetListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: DatasetListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { DatasetListPageAsync.of(this, params, it) } + .let { + DatasetListPageAsync.builder() + .service(DatasetServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Delete a dataset object by its id */ - override suspend fun delete( - params: DatasetDeleteParams, - requestOptions: RequestOptions - ): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "dataset", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: DatasetDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val feedbackHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val feedbackHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Log feedback for a set of dataset events */ - override suspend fun feedback( - params: DatasetFeedbackParams, - requestOptions: RequestOptions - ): FeedbackResponseSchema { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset", params.getPathParam(0), "feedback") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { feedbackHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun feedback( + params: DatasetFeedbackParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "feedback") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { feedbackHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a dataset. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body - */ - override suspend fun fetch( - params: DatasetFetchParams, - requestOptions: RequestOptions - ): FetchDatasetEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { fetchHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun fetch( + params: DatasetFetchParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "fetch") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { fetchHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchPostHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchPostHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a dataset. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query - */ - override suspend fun fetchPost( - params: DatasetFetchPostParams, - requestOptions: RequestOptions - ): FetchDatasetEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { fetchPostHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun fetchPost( + params: DatasetFetchPostParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "fetch") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { fetchPostHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val insertHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val insertHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Insert a set of events into the dataset */ - override suspend fun insert( - params: DatasetInsertParams, - requestOptions: RequestOptions - ): InsertEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset", params.getPathParam(0), "insert") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { insertHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "insert") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { insertHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val summarizeHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val summarizeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Summarize dataset */ - override suspend fun summarize( - params: DatasetSummarizeParams, - requestOptions: RequestOptions - ): SummarizeDatasetResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset", params.getPathParam(0), "summarize") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { summarizeHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun summarize( + params: DatasetSummarizeParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "summarize") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { summarizeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsync.kt index 965185f2..d382759c 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.EnvVar import com.braintrustdata.api.models.EnvVarCreateParams import com.braintrustdata.api.models.EnvVarDeleteParams @@ -13,32 +13,63 @@ import com.braintrustdata.api.models.EnvVarListResponse import com.braintrustdata.api.models.EnvVarReplaceParams import com.braintrustdata.api.models.EnvVarRetrieveParams import com.braintrustdata.api.models.EnvVarUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface EnvVarServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): EnvVarServiceAsync + /** * Create a new env_var. If there is an existing env_var with the same name as the one specified * in the request, will return the existing env_var unmodified */ suspend fun create( params: EnvVarCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar /** Get an env_var object by its id */ + suspend fun retrieve( + envVarId: String, + params: EnvVarRetrieveParams = EnvVarRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): EnvVar = retrieve(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: EnvVarRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar + /** @see retrieve */ + suspend fun retrieve(envVarId: String, requestOptions: RequestOptions): EnvVar = + retrieve(envVarId, EnvVarRetrieveParams.none(), requestOptions) + /** * Partially update an env_var object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + envVarId: String, + params: EnvVarUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): EnvVar = update(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see update */ suspend fun update( params: EnvVarUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar /** @@ -46,22 +77,158 @@ interface EnvVarServiceAsync { * recently-created env_vars coming first */ suspend fun list( - params: EnvVarListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: EnvVarListParams = EnvVarListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVarListResponse + /** @see list */ + suspend fun list(requestOptions: RequestOptions): EnvVarListResponse = + list(EnvVarListParams.none(), requestOptions) + /** Delete an env_var object by its id */ + suspend fun delete( + envVarId: String, + params: EnvVarDeleteParams = EnvVarDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): EnvVar = delete(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: EnvVarDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar + /** @see delete */ + suspend fun delete(envVarId: String, requestOptions: RequestOptions): EnvVar = + delete(envVarId, EnvVarDeleteParams.none(), requestOptions) + /** * Create or replace env_var. If there is an existing env_var with the same name as the one * specified in the request, will replace the existing env_var with the provided fields */ suspend fun replace( params: EnvVarReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar + + /** + * A view of [EnvVarServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): EnvVarServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/env_var`, but is otherwise the same as + * [EnvVarServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: EnvVarCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/env_var/{env_var_id}`, but is otherwise the same + * as [EnvVarServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + envVarId: String, + params: EnvVarRetrieveParams = EnvVarRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: EnvVarRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + envVarId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = retrieve(envVarId, EnvVarRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/env_var/{env_var_id}`, but is otherwise the + * same as [EnvVarServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + envVarId: String, + params: EnvVarUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: EnvVarUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/env_var`, but is otherwise the same as + * [EnvVarServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: EnvVarListParams = EnvVarListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(EnvVarListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/env_var/{env_var_id}`, but is otherwise the + * same as [EnvVarServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + envVarId: String, + params: EnvVarDeleteParams = EnvVarDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: EnvVarDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + envVarId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = delete(envVarId, EnvVarDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/env_var`, but is otherwise the same as + * [EnvVarServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: EnvVarReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsyncImpl.kt index 4e7a65c1..2a1c06dd 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsyncImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.EnvVar import com.braintrustdata.api.models.EnvVarCreateParams import com.braintrustdata.api.models.EnvVarDeleteParams @@ -16,200 +24,242 @@ import com.braintrustdata.api.models.EnvVarListResponse import com.braintrustdata.api.models.EnvVarReplaceParams import com.braintrustdata.api.models.EnvVarRetrieveParams import com.braintrustdata.api.models.EnvVarUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class EnvVarServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : EnvVarServiceAsync { +class EnvVarServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + EnvVarServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: EnvVarServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): EnvVarServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): EnvVarServiceAsync = + EnvVarServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new env_var. If there is an existing env_var with the same name as the one specified - * in the request, will return the existing env_var unmodified - */ override suspend fun create( params: EnvVarCreateParams, - requestOptions: RequestOptions - ): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "env_var") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): EnvVar = + // post /v1/env_var + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: EnvVarRetrieveParams, + requestOptions: RequestOptions, + ): EnvVar = + // get /v1/env_var/{env_var_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: EnvVarUpdateParams, + requestOptions: RequestOptions, + ): EnvVar = + // patch /v1/env_var/{env_var_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: EnvVarListParams, + requestOptions: RequestOptions, + ): EnvVarListResponse = + // get /v1/env_var + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: EnvVarDeleteParams, + requestOptions: RequestOptions, + ): EnvVar = + // delete /v1/env_var/{env_var_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace( + params: EnvVarReplaceParams, + requestOptions: RequestOptions, + ): EnvVar = + // put /v1/env_var + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + EnvVarServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): EnvVarServiceAsync.WithRawResponse = + EnvVarServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: EnvVarCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Get an env_var object by its id */ - override suspend fun retrieve( - params: EnvVarRetrieveParams, - requestOptions: RequestOptions - ): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "env_var", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: EnvVarRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("envVarId", params.envVarId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * Partially update an env_var object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: EnvVarUpdateParams, - requestOptions: RequestOptions - ): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "env_var", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: EnvVarUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("envVarId", params.envVarId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all env_vars. The env_vars are sorted by creation date, with the most - * recently-created env_vars coming first - */ - override suspend fun list( - params: EnvVarListParams, - requestOptions: RequestOptions - ): EnvVarListResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "env_var") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: EnvVarListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Delete an env_var object by its id */ - override suspend fun delete( - params: EnvVarDeleteParams, - requestOptions: RequestOptions - ): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "env_var", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: EnvVarDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("envVarId", params.envVarId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace env_var. If there is an existing env_var with the same name as the one - * specified in the request, will replace the existing env_var with the provided fields - */ - override suspend fun replace( - params: EnvVarReplaceParams, - requestOptions: RequestOptions - ): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "env_var") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun replace( + params: EnvVarReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsync.kt index a5db23db..59ab41cc 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsync.kt @@ -1,15 +1,28 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.EvalCreateParams import com.braintrustdata.api.models.SummarizeExperimentResponse +import com.google.errorprone.annotations.MustBeClosed interface EvalServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): EvalServiceAsync + /** * Launch an evaluation. This is the API-equivalent of the `Eval` function that is built into * the Braintrust SDK. In the Eval API, you provide pointers to a dataset, task function, and @@ -19,6 +32,27 @@ interface EvalServiceAsync { */ suspend fun create( params: EvalCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): SummarizeExperimentResponse + + /** A view of [EvalServiceAsync] 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: (ClientOptions.Builder) -> Unit): EvalServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/eval`, but is otherwise the same as + * [EvalServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: EvalCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsyncImpl.kt index a5708ed1..b1baa708 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/EvalServiceAsyncImpl.kt @@ -4,57 +4,78 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.EvalCreateParams import com.braintrustdata.api.models.SummarizeExperimentResponse -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class EvalServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : EvalServiceAsync { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - /** - * Launch an evaluation. This is the API-equivalent of the `Eval` function that is built into - * the Braintrust SDK. In the Eval API, you provide pointers to a dataset, task function, and - * scoring functions. The API will then run the evaluation, create an experiment, and return the - * results along with a link to the experiment. To learn more about evals, see the - * [Evals guide](https://www.braintrust.dev/docs/guides/evals). - */ + +class EvalServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + EvalServiceAsync { + + private val withRawResponse: EvalServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): EvalServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): EvalServiceAsync = + EvalServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + override suspend fun create( params: EvalCreateParams, - requestOptions: RequestOptions - ): SummarizeExperimentResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "eval") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): SummarizeExperimentResponse = + // post /v1/eval + withRawResponse().create(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + EvalServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): EvalServiceAsync.WithRawResponse = + EvalServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: EvalCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "eval") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsync.kt index 61ee0ea0..dfb91cdd 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Experiment import com.braintrustdata.api.models.ExperimentCreateParams import com.braintrustdata.api.models.ExperimentDeleteParams @@ -21,82 +21,436 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchExperimentEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeExperimentResponse +import com.google.errorprone.annotations.MustBeClosed interface ExperimentServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): ExperimentServiceAsync + /** * Create a new experiment. If there is an existing experiment in the project with the same name * as the one specified in the request, will return the existing experiment unmodified */ suspend fun create( params: ExperimentCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment /** Get an experiment object by its id */ + suspend fun retrieve( + experimentId: String, + params: ExperimentRetrieveParams = ExperimentRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Experiment = retrieve(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: ExperimentRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment + /** @see retrieve */ + suspend fun retrieve(experimentId: String, requestOptions: RequestOptions): Experiment = + retrieve(experimentId, ExperimentRetrieveParams.none(), requestOptions) + /** * Partially update an experiment object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + experimentId: String, + params: ExperimentUpdateParams = ExperimentUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Experiment = update(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see update */ suspend fun update( params: ExperimentUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment + /** @see update */ + suspend fun update(experimentId: String, requestOptions: RequestOptions): Experiment = + update(experimentId, ExperimentUpdateParams.none(), requestOptions) + /** * List out all experiments. The experiments are sorted by creation date, with the most * recently-created experiments coming first */ suspend fun list( - params: ExperimentListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ExperimentListParams = ExperimentListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ExperimentListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): ExperimentListPageAsync = + list(ExperimentListParams.none(), requestOptions) + /** Delete an experiment object by its id */ + suspend fun delete( + experimentId: String, + params: ExperimentDeleteParams = ExperimentDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Experiment = delete(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: ExperimentDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment + /** @see delete */ + suspend fun delete(experimentId: String, requestOptions: RequestOptions): Experiment = + delete(experimentId, ExperimentDeleteParams.none(), requestOptions) + /** Log feedback for a set of experiment events */ + suspend fun feedback( + experimentId: String, + params: ExperimentFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FeedbackResponseSchema = + feedback(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see feedback */ suspend fun feedback( params: ExperimentFeedbackParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FeedbackResponseSchema /** * Fetch the events in an experiment. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body + * parameters in the URL query rather than in the request body. For more complex queries, use + * the `POST /btql` endpoint. */ + suspend fun fetch( + experimentId: String, + params: ExperimentFetchParams = ExperimentFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchExperimentEventsResponse = + fetch(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetch */ suspend fun fetch( params: ExperimentFetchParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchExperimentEventsResponse + /** @see fetch */ + suspend fun fetch( + experimentId: String, + requestOptions: RequestOptions, + ): FetchExperimentEventsResponse = + fetch(experimentId, ExperimentFetchParams.none(), requestOptions) + /** * Fetch the events in an experiment. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query + * parameters in the request body rather than in the URL query. For more complex queries, use + * the `POST /btql` endpoint. */ + suspend fun fetchPost( + experimentId: String, + params: ExperimentFetchPostParams = ExperimentFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchExperimentEventsResponse = + fetchPost(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetchPost */ suspend fun fetchPost( params: ExperimentFetchPostParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchExperimentEventsResponse + /** @see fetchPost */ + suspend fun fetchPost( + experimentId: String, + requestOptions: RequestOptions, + ): FetchExperimentEventsResponse = + fetchPost(experimentId, ExperimentFetchPostParams.none(), requestOptions) + /** Insert a set of events into the experiment */ suspend fun insert( + experimentId: String, params: ExperimentInsertParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): InsertEventsResponse = + insert(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see insert */ + suspend fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), ): InsertEventsResponse /** Summarize experiment */ + suspend fun summarize( + experimentId: String, + params: ExperimentSummarizeParams = ExperimentSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SummarizeExperimentResponse = + summarize(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see summarize */ suspend fun summarize( params: ExperimentSummarizeParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): SummarizeExperimentResponse + + /** @see summarize */ + suspend fun summarize( + experimentId: String, + requestOptions: RequestOptions, + ): SummarizeExperimentResponse = + summarize(experimentId, ExperimentSummarizeParams.none(), requestOptions) + + /** + * A view of [ExperimentServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): ExperimentServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/experiment`, but is otherwise the same as + * [ExperimentServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: ExperimentCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/experiment/{experiment_id}`, but is otherwise + * the same as [ExperimentServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + experimentId: String, + params: ExperimentRetrieveParams = ExperimentRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: ExperimentRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(experimentId, ExperimentRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/experiment/{experiment_id}`, but is otherwise + * the same as [ExperimentServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + experimentId: String, + params: ExperimentUpdateParams = ExperimentUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: ExperimentUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(experimentId, ExperimentUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/experiment`, but is otherwise the same as + * [ExperimentServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: ExperimentListParams = ExperimentListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ExperimentListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/experiment/{experiment_id}`, but is otherwise + * the same as [ExperimentServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + experimentId: String, + params: ExperimentDeleteParams = ExperimentDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: ExperimentDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(experimentId, ExperimentDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/experiment/{experiment_id}/feedback`, but is + * otherwise the same as [ExperimentServiceAsync.feedback]. + */ + @MustBeClosed + suspend fun feedback( + experimentId: String, + params: ExperimentFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + feedback(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see feedback */ + @MustBeClosed + suspend fun feedback( + params: ExperimentFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/experiment/{experiment_id}/fetch`, but is + * otherwise the same as [ExperimentServiceAsync.fetch]. + */ + @MustBeClosed + suspend fun fetch( + experimentId: String, + params: ExperimentFetchParams = ExperimentFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetch(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetch */ + @MustBeClosed + suspend fun fetch( + params: ExperimentFetchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetch */ + @MustBeClosed + suspend fun fetch( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetch(experimentId, ExperimentFetchParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/experiment/{experiment_id}/fetch`, but is + * otherwise the same as [ExperimentServiceAsync.fetchPost]. + */ + @MustBeClosed + suspend fun fetchPost( + experimentId: String, + params: ExperimentFetchPostParams = ExperimentFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetchPost(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetchPost */ + @MustBeClosed + suspend fun fetchPost( + params: ExperimentFetchPostParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetchPost */ + @MustBeClosed + suspend fun fetchPost( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetchPost(experimentId, ExperimentFetchPostParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/experiment/{experiment_id}/insert`, but is + * otherwise the same as [ExperimentServiceAsync.insert]. + */ + @MustBeClosed + suspend fun insert( + experimentId: String, + params: ExperimentInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + insert(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see insert */ + @MustBeClosed + suspend fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/experiment/{experiment_id}/summarize`, but is + * otherwise the same as [ExperimentServiceAsync.summarize]. + */ + @MustBeClosed + suspend fun summarize( + experimentId: String, + params: ExperimentSummarizeParams = ExperimentSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + summarize(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see summarize */ + @MustBeClosed + suspend fun summarize( + params: ExperimentSummarizeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see summarize */ + @MustBeClosed + suspend fun summarize( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + summarize(experimentId, ExperimentSummarizeParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsyncImpl.kt index 6d06c1fb..c009a1e3 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsyncImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Experiment import com.braintrustdata.api.models.ExperimentCreateParams import com.braintrustdata.api.models.ExperimentDeleteParams @@ -16,6 +24,7 @@ import com.braintrustdata.api.models.ExperimentFetchParams import com.braintrustdata.api.models.ExperimentFetchPostParams import com.braintrustdata.api.models.ExperimentInsertParams import com.braintrustdata.api.models.ExperimentListPageAsync +import com.braintrustdata.api.models.ExperimentListPageResponse import com.braintrustdata.api.models.ExperimentListParams import com.braintrustdata.api.models.ExperimentRetrieveParams import com.braintrustdata.api.models.ExperimentSummarizeParams @@ -24,322 +33,407 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchExperimentEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeExperimentResponse -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ExperimentServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : ExperimentServiceAsync { +class ExperimentServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + ExperimentServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ExperimentServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ExperimentServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ExperimentServiceAsync = + ExperimentServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new experiment. If there is an existing experiment in the project with the same name - * as the one specified in the request, will return the existing experiment unmodified - */ override suspend fun create( params: ExperimentCreateParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Experiment = + // post /v1/experiment + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: ExperimentRetrieveParams, + requestOptions: RequestOptions, + ): Experiment = + // get /v1/experiment/{experiment_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: ExperimentUpdateParams, + requestOptions: RequestOptions, + ): Experiment = + // patch /v1/experiment/{experiment_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: ExperimentListParams, + requestOptions: RequestOptions, + ): ExperimentListPageAsync = + // get /v1/experiment + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: ExperimentDeleteParams, + requestOptions: RequestOptions, + ): Experiment = + // delete /v1/experiment/{experiment_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun feedback( + params: ExperimentFeedbackParams, + requestOptions: RequestOptions, + ): FeedbackResponseSchema = + // post /v1/experiment/{experiment_id}/feedback + withRawResponse().feedback(params, requestOptions).parse() + + override suspend fun fetch( + params: ExperimentFetchParams, + requestOptions: RequestOptions, + ): FetchExperimentEventsResponse = + // get /v1/experiment/{experiment_id}/fetch + withRawResponse().fetch(params, requestOptions).parse() + + override suspend fun fetchPost( + params: ExperimentFetchPostParams, + requestOptions: RequestOptions, + ): FetchExperimentEventsResponse = + // post /v1/experiment/{experiment_id}/fetch + withRawResponse().fetchPost(params, requestOptions).parse() + + override suspend fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions, + ): InsertEventsResponse = + // post /v1/experiment/{experiment_id}/insert + withRawResponse().insert(params, requestOptions).parse() + + override suspend fun summarize( + params: ExperimentSummarizeParams, + requestOptions: RequestOptions, + ): SummarizeExperimentResponse = + // get /v1/experiment/{experiment_id}/summarize + withRawResponse().summarize(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ExperimentServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ExperimentServiceAsync.WithRawResponse = + ExperimentServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: ExperimentCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get an experiment object by its id */ - override suspend fun retrieve( - params: ExperimentRetrieveParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: ExperimentRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update an experiment object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: ExperimentUpdateParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "experiment", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: ExperimentUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all experiments. The experiments are sorted by creation date, with the most - * recently-created experiments coming first - */ - override suspend fun list( - params: ExperimentListParams, - requestOptions: RequestOptions - ): ExperimentListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: ExperimentListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { ExperimentListPageAsync.of(this, params, it) } + .let { + ExperimentListPageAsync.builder() + .service(ExperimentServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete an experiment object by its id */ - override suspend fun delete( - params: ExperimentDeleteParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "experiment", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: ExperimentDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val feedbackHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val feedbackHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Log feedback for a set of experiment events */ - override suspend fun feedback( - params: ExperimentFeedbackParams, - requestOptions: RequestOptions - ): FeedbackResponseSchema { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment", params.getPathParam(0), "feedback") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { feedbackHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun feedback( + params: ExperimentFeedbackParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "feedback") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { feedbackHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in an experiment. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body - */ - override suspend fun fetch( - params: ExperimentFetchParams, - requestOptions: RequestOptions - ): FetchExperimentEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { fetchHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun fetch( + params: ExperimentFetchParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "fetch") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { fetchHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchPostHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchPostHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in an experiment. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query - */ - override suspend fun fetchPost( - params: ExperimentFetchPostParams, - requestOptions: RequestOptions - ): FetchExperimentEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { fetchPostHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun fetchPost( + params: ExperimentFetchPostParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "fetch") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { fetchPostHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val insertHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val insertHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Insert a set of events into the experiment */ - override suspend fun insert( - params: ExperimentInsertParams, - requestOptions: RequestOptions - ): InsertEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment", params.getPathParam(0), "insert") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { insertHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "insert") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { insertHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val summarizeHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val summarizeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Summarize experiment */ - override suspend fun summarize( - params: ExperimentSummarizeParams, - requestOptions: RequestOptions - ): SummarizeExperimentResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment", params.getPathParam(0), "summarize") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { summarizeHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun summarize( + params: ExperimentSummarizeParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "summarize") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { summarizeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsync.kt index 6ee2173b..fab17ae6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Function import com.braintrustdata.api.models.FunctionCreateParams import com.braintrustdata.api.models.FunctionDeleteParams @@ -15,54 +15,118 @@ import com.braintrustdata.api.models.FunctionListParams import com.braintrustdata.api.models.FunctionReplaceParams import com.braintrustdata.api.models.FunctionRetrieveParams import com.braintrustdata.api.models.FunctionUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface FunctionServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): FunctionServiceAsync + /** * Create a new function. If there is an existing function in the project with the same slug as * the one specified in the request, will return the existing function unmodified */ suspend fun create( params: FunctionCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function /** Get a function object by its id */ + suspend fun retrieve( + functionId: String, + params: FunctionRetrieveParams = FunctionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Function = retrieve(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: FunctionRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + /** @see retrieve */ + suspend fun retrieve(functionId: String, requestOptions: RequestOptions): Function = + retrieve(functionId, FunctionRetrieveParams.none(), requestOptions) + /** * Partially update a function object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + functionId: String, + params: FunctionUpdateParams = FunctionUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Function = update(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see update */ suspend fun update( params: FunctionUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + /** @see update */ + suspend fun update(functionId: String, requestOptions: RequestOptions): Function = + update(functionId, FunctionUpdateParams.none(), requestOptions) + /** * List out all functions. The functions are sorted by creation date, with the most * recently-created functions coming first */ suspend fun list( - params: FunctionListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: FunctionListParams = FunctionListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): FunctionListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): FunctionListPageAsync = + list(FunctionListParams.none(), requestOptions) + /** Delete a function object by its id */ + suspend fun delete( + functionId: String, + params: FunctionDeleteParams = FunctionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Function = delete(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: FunctionDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + /** @see delete */ + suspend fun delete(functionId: String, requestOptions: RequestOptions): Function = + delete(functionId, FunctionDeleteParams.none(), requestOptions) + /** Invoke a function. */ + suspend fun invoke( + functionId: String, + params: FunctionInvokeParams = FunctionInvokeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FunctionInvokeResponse? = + invoke(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see invoke */ suspend fun invoke( params: FunctionInvokeParams, - requestOptions: RequestOptions = RequestOptions.none() - ): FunctionInvokeResponse + requestOptions: RequestOptions = RequestOptions.none(), + ): FunctionInvokeResponse? + + /** @see invoke */ + suspend fun invoke( + functionId: String, + requestOptions: RequestOptions, + ): FunctionInvokeResponse? = invoke(functionId, FunctionInvokeParams.none(), requestOptions) /** * Create or replace function. If there is an existing function in the project with the same @@ -71,6 +135,164 @@ interface FunctionServiceAsync { */ suspend fun replace( params: FunctionReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + + /** + * A view of [FunctionServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): FunctionServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/function`, but is otherwise the same as + * [FunctionServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: FunctionCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/function/{function_id}`, but is otherwise the + * same as [FunctionServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + functionId: String, + params: FunctionRetrieveParams = FunctionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: FunctionRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + functionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(functionId, FunctionRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/function/{function_id}`, but is otherwise the + * same as [FunctionServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + functionId: String, + params: FunctionUpdateParams = FunctionUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: FunctionUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + functionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(functionId, FunctionUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/function`, but is otherwise the same as + * [FunctionServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: FunctionListParams = FunctionListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(FunctionListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/function/{function_id}`, but is otherwise the + * same as [FunctionServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + functionId: String, + params: FunctionDeleteParams = FunctionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: FunctionDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + functionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(functionId, FunctionDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/function/{function_id}/invoke`, but is + * otherwise the same as [FunctionServiceAsync.invoke]. + */ + @MustBeClosed + suspend fun invoke( + functionId: String, + params: FunctionInvokeParams = FunctionInvokeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + invoke(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see invoke */ + @MustBeClosed + suspend fun invoke( + params: FunctionInvokeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see invoke */ + @MustBeClosed + suspend fun invoke( + functionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + invoke(functionId, FunctionInvokeParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/function`, but is otherwise the same as + * [FunctionServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: FunctionReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsyncImpl.kt index d00cd2ec..f1eeeac0 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsyncImpl.kt @@ -4,240 +4,315 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Function import com.braintrustdata.api.models.FunctionCreateParams import com.braintrustdata.api.models.FunctionDeleteParams import com.braintrustdata.api.models.FunctionInvokeParams import com.braintrustdata.api.models.FunctionInvokeResponse import com.braintrustdata.api.models.FunctionListPageAsync +import com.braintrustdata.api.models.FunctionListPageResponse import com.braintrustdata.api.models.FunctionListParams import com.braintrustdata.api.models.FunctionReplaceParams import com.braintrustdata.api.models.FunctionRetrieveParams import com.braintrustdata.api.models.FunctionUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class FunctionServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : FunctionServiceAsync { +class FunctionServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + FunctionServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: FunctionServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): FunctionServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): FunctionServiceAsync = + FunctionServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new function. If there is an existing function in the project with the same slug as - * the one specified in the request, will return the existing function unmodified - */ override suspend fun create( params: FunctionCreateParams, - requestOptions: RequestOptions - ): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "function") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Function = + // post /v1/function + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: FunctionRetrieveParams, + requestOptions: RequestOptions, + ): Function = + // get /v1/function/{function_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: FunctionUpdateParams, + requestOptions: RequestOptions, + ): Function = + // patch /v1/function/{function_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: FunctionListParams, + requestOptions: RequestOptions, + ): FunctionListPageAsync = + // get /v1/function + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: FunctionDeleteParams, + requestOptions: RequestOptions, + ): Function = + // delete /v1/function/{function_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun invoke( + params: FunctionInvokeParams, + requestOptions: RequestOptions, + ): FunctionInvokeResponse? = + // post /v1/function/{function_id}/invoke + withRawResponse().invoke(params, requestOptions).parse() + + override suspend fun replace( + params: FunctionReplaceParams, + requestOptions: RequestOptions, + ): Function = + // put /v1/function + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + FunctionServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): FunctionServiceAsync.WithRawResponse = + FunctionServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: FunctionCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get a function object by its id */ - override suspend fun retrieve( - params: FunctionRetrieveParams, - requestOptions: RequestOptions - ): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "function", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: FunctionRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update a function object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: FunctionUpdateParams, - requestOptions: RequestOptions - ): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "function", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: FunctionUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all functions. The functions are sorted by creation date, with the most - * recently-created functions coming first - */ - override suspend fun list( - params: FunctionListParams, - requestOptions: RequestOptions - ): FunctionListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "function") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: FunctionListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { FunctionListPageAsync.of(this, params, it) } + .let { + FunctionListPageAsync.builder() + .service(FunctionServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete a function object by its id */ - override suspend fun delete( - params: FunctionDeleteParams, - requestOptions: RequestOptions - ): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "function", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: FunctionDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val invokeHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val invokeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Invoke a function. */ - override suspend fun invoke( - params: FunctionInvokeParams, - requestOptions: RequestOptions - ): FunctionInvokeResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "function", params.getPathParam(0), "invoke") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response.use { invokeHandler.handle(it) } + override suspend fun invoke( + params: FunctionInvokeParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0), "invoke") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { invokeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it?.validate() + } + } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace function. If there is an existing function in the project with the same - * slug as the one specified in the request, will replace the existing function with the - * provided fields - */ - override suspend fun replace( - params: FunctionReplaceParams, - requestOptions: RequestOptions - ): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "function") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun replace( + params: FunctionReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsync.kt index d9fff275..d28c68a5 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Group import com.braintrustdata.api.models.GroupCreateParams import com.braintrustdata.api.models.GroupDeleteParams @@ -13,55 +13,231 @@ import com.braintrustdata.api.models.GroupListParams import com.braintrustdata.api.models.GroupReplaceParams import com.braintrustdata.api.models.GroupRetrieveParams import com.braintrustdata.api.models.GroupUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface GroupServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): GroupServiceAsync + /** * Create a new group. If there is an existing group with the same name as the one specified in * the request, will return the existing group unmodified */ suspend fun create( params: GroupCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group /** Get a group object by its id */ + suspend fun retrieve( + groupId: String, + params: GroupRetrieveParams = GroupRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Group = retrieve(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: GroupRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + /** @see retrieve */ + suspend fun retrieve(groupId: String, requestOptions: RequestOptions): Group = + retrieve(groupId, GroupRetrieveParams.none(), requestOptions) + /** * Partially update a group object. Specify the fields to update in the payload. Any object-type * fields will be deep-merged with existing content. Currently we do not support removing fields * or setting them to null. */ + suspend fun update( + groupId: String, + params: GroupUpdateParams = GroupUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Group = update(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see update */ suspend fun update( params: GroupUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + /** @see update */ + suspend fun update(groupId: String, requestOptions: RequestOptions): Group = + update(groupId, GroupUpdateParams.none(), requestOptions) + /** * List out all groups. The groups are sorted by creation date, with the most recently-created * groups coming first */ suspend fun list( - params: GroupListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: GroupListParams = GroupListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): GroupListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): GroupListPageAsync = + list(GroupListParams.none(), requestOptions) + /** Delete a group object by its id */ + suspend fun delete( + groupId: String, + params: GroupDeleteParams = GroupDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Group = delete(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: GroupDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + /** @see delete */ + suspend fun delete(groupId: String, requestOptions: RequestOptions): Group = + delete(groupId, GroupDeleteParams.none(), requestOptions) + /** * Create or replace group. If there is an existing group with the same name as the one * specified in the request, will replace the existing group with the provided fields */ suspend fun replace( params: GroupReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + + /** A view of [GroupServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): GroupServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/group`, but is otherwise the same as + * [GroupServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: GroupCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/group/{group_id}`, but is otherwise the same as + * [GroupServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + groupId: String, + params: GroupRetrieveParams = GroupRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: GroupRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + groupId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = retrieve(groupId, GroupRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/group/{group_id}`, but is otherwise the same + * as [GroupServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + groupId: String, + params: GroupUpdateParams = GroupUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: GroupUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + groupId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = update(groupId, GroupUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/group`, but is otherwise the same as + * [GroupServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: GroupListParams = GroupListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(GroupListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/group/{group_id}`, but is otherwise the same + * as [GroupServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + groupId: String, + params: GroupDeleteParams = GroupDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: GroupDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + groupId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = delete(groupId, GroupDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/group`, but is otherwise the same as + * [GroupServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: GroupReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsyncImpl.kt index 2e0e7ab6..cf9bb410 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/GroupServiceAsyncImpl.kt @@ -4,205 +4,261 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Group import com.braintrustdata.api.models.GroupCreateParams import com.braintrustdata.api.models.GroupDeleteParams import com.braintrustdata.api.models.GroupListPageAsync +import com.braintrustdata.api.models.GroupListPageResponse import com.braintrustdata.api.models.GroupListParams import com.braintrustdata.api.models.GroupReplaceParams import com.braintrustdata.api.models.GroupRetrieveParams import com.braintrustdata.api.models.GroupUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class GroupServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : GroupServiceAsync { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new group. If there is an existing group with the same name as the one specified in - * the request, will return the existing group unmodified - */ - override suspend fun create(params: GroupCreateParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "group") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } + +class GroupServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + GroupServiceAsync { + + private val withRawResponse: GroupServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withRawResponse(): GroupServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): GroupServiceAsync = + GroupServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + + override suspend fun create(params: GroupCreateParams, requestOptions: RequestOptions): Group = + // post /v1/group + withRawResponse().create(params, requestOptions).parse() - /** Get a group object by its id */ override suspend fun retrieve( params: GroupRetrieveParams, - requestOptions: RequestOptions - ): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "group", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Group = + // get /v1/group/{group_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update(params: GroupUpdateParams, requestOptions: RequestOptions): Group = + // patch /v1/group/{group_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: GroupListParams, + requestOptions: RequestOptions, + ): GroupListPageAsync = + // get /v1/group + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete(params: GroupDeleteParams, requestOptions: RequestOptions): Group = + // delete /v1/group/{group_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace( + params: GroupReplaceParams, + requestOptions: RequestOptions, + ): Group = + // put /v1/group + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GroupServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): GroupServiceAsync.WithRawResponse = + GroupServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: GroupCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a group object. Specify the fields to update in the payload. Any object-type - * fields will be deep-merged with existing content. Currently we do not support removing fields - * or setting them to null. - */ - override suspend fun update(params: GroupUpdateParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "group", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: GroupRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("groupId", params.groupId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * List out all groups. The groups are sorted by creation date, with the most recently-created - * groups coming first - */ - override suspend fun list( - params: GroupListParams, - requestOptions: RequestOptions - ): GroupListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "group") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: GroupUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("groupId", params.groupId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { GroupListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a group object by its id */ - override suspend fun delete(params: GroupDeleteParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "group", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun list( + params: GroupListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + .let { + GroupListPageAsync.builder() + .service(GroupServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace group. If there is an existing group with the same name as the one - * specified in the request, will replace the existing group with the provided fields - */ - override suspend fun replace( - params: GroupReplaceParams, - requestOptions: RequestOptions - ): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "group") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: GroupDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("groupId", params.groupId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun replace( + params: GroupReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsync.kt index 1897ede2..2bfdc06f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Organization import com.braintrustdata.api.models.OrganizationDeleteParams import com.braintrustdata.api.models.OrganizationListPageAsync @@ -12,39 +12,208 @@ import com.braintrustdata.api.models.OrganizationListParams import com.braintrustdata.api.models.OrganizationRetrieveParams import com.braintrustdata.api.models.OrganizationUpdateParams import com.braintrustdata.api.services.async.organizations.MemberServiceAsync +import com.google.errorprone.annotations.MustBeClosed interface OrganizationServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): OrganizationServiceAsync + fun members(): MemberServiceAsync /** Get an organization object by its id */ + suspend fun retrieve( + organizationId: String, + params: OrganizationRetrieveParams = OrganizationRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Organization = + retrieve(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: OrganizationRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Organization + /** @see retrieve */ + suspend fun retrieve(organizationId: String, requestOptions: RequestOptions): Organization = + retrieve(organizationId, OrganizationRetrieveParams.none(), requestOptions) + /** * Partially update an organization object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + organizationId: String, + params: OrganizationUpdateParams = OrganizationUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Organization = + update(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see update */ suspend fun update( params: OrganizationUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Organization + /** @see update */ + suspend fun update(organizationId: String, requestOptions: RequestOptions): Organization = + update(organizationId, OrganizationUpdateParams.none(), requestOptions) + /** * List out all organizations. The organizations are sorted by creation date, with the most * recently-created organizations coming first */ suspend fun list( - params: OrganizationListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: OrganizationListParams = OrganizationListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): OrganizationListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): OrganizationListPageAsync = + list(OrganizationListParams.none(), requestOptions) + /** Delete an organization object by its id */ + suspend fun delete( + organizationId: String, + params: OrganizationDeleteParams = OrganizationDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Organization = + delete(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: OrganizationDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Organization + + /** @see delete */ + suspend fun delete(organizationId: String, requestOptions: RequestOptions): Organization = + delete(organizationId, OrganizationDeleteParams.none(), requestOptions) + + /** + * A view of [OrganizationServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): OrganizationServiceAsync.WithRawResponse + + fun members(): MemberServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `get /v1/organization/{organization_id}`, but is + * otherwise the same as [OrganizationServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + organizationId: String, + params: OrganizationRetrieveParams = OrganizationRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: OrganizationRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + organizationId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(organizationId, OrganizationRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/organization/{organization_id}`, but is + * otherwise the same as [OrganizationServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + organizationId: String, + params: OrganizationUpdateParams = OrganizationUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: OrganizationUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + organizationId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(organizationId, OrganizationUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/organization`, but is otherwise the same as + * [OrganizationServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: OrganizationListParams = OrganizationListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list( + requestOptions: RequestOptions + ): HttpResponseFor = + list(OrganizationListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/organization/{organization_id}`, but is + * otherwise the same as [OrganizationServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + organizationId: String, + params: OrganizationDeleteParams = OrganizationDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: OrganizationDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + organizationId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(organizationId, OrganizationDeleteParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsyncImpl.kt index ba332821..a9111eac 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsyncImpl.kt @@ -4,154 +4,215 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Organization import com.braintrustdata.api.models.OrganizationDeleteParams import com.braintrustdata.api.models.OrganizationListPageAsync +import com.braintrustdata.api.models.OrganizationListPageResponse import com.braintrustdata.api.models.OrganizationListParams import com.braintrustdata.api.models.OrganizationRetrieveParams import com.braintrustdata.api.models.OrganizationUpdateParams import com.braintrustdata.api.services.async.organizations.MemberServiceAsync import com.braintrustdata.api.services.async.organizations.MemberServiceAsyncImpl -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class OrganizationServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : OrganizationServiceAsync { +class OrganizationServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + OrganizationServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: OrganizationServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } private val members: MemberServiceAsync by lazy { MemberServiceAsyncImpl(clientOptions) } - override fun members(): MemberServiceAsync = members + override fun withRawResponse(): OrganizationServiceAsync.WithRawResponse = withRawResponse - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): OrganizationServiceAsync = + OrganizationServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun members(): MemberServiceAsync = members - /** Get an organization object by its id */ override suspend fun retrieve( params: OrganizationRetrieveParams, - requestOptions: RequestOptions - ): Organization { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "organization", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Organization = + // get /v1/organization/{organization_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: OrganizationUpdateParams, + requestOptions: RequestOptions, + ): Organization = + // patch /v1/organization/{organization_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: OrganizationListParams, + requestOptions: RequestOptions, + ): OrganizationListPageAsync = + // get /v1/organization + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: OrganizationDeleteParams, + requestOptions: RequestOptions, + ): Organization = + // delete /v1/organization/{organization_id} + withRawResponse().delete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + OrganizationServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + private val members: MemberServiceAsync.WithRawResponse by lazy { + MemberServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): OrganizationServiceAsync.WithRawResponse = + OrganizationServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + override fun members(): MemberServiceAsync.WithRawResponse = members + + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: OrganizationRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("organizationId", params.organizationId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update an organization object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: OrganizationUpdateParams, - requestOptions: RequestOptions - ): Organization { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "organization", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: OrganizationUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("organizationId", params.organizationId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all organizations. The organizations are sorted by creation date, with the most - * recently-created organizations coming first - */ - override suspend fun list( - params: OrganizationListParams, - requestOptions: RequestOptions - ): OrganizationListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "organization") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: OrganizationListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + OrganizationListPageAsync.builder() + .service(OrganizationServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { OrganizationListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete an organization object by its id */ - override suspend fun delete( - params: OrganizationDeleteParams, - requestOptions: RequestOptions - ): Organization { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "organization", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: OrganizationDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("organizationId", params.organizationId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsync.kt index 34d1e8e3..02cd59c9 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.ProjectScore import com.braintrustdata.api.models.ProjectScoreCreateParams import com.braintrustdata.api.models.ProjectScoreDeleteParams @@ -13,9 +13,22 @@ import com.braintrustdata.api.models.ProjectScoreListParams import com.braintrustdata.api.models.ProjectScoreReplaceParams import com.braintrustdata.api.models.ProjectScoreRetrieveParams import com.braintrustdata.api.models.ProjectScoreUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface ProjectScoreServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): ProjectScoreServiceAsync + /** * Create a new project_score. If there is an existing project_score in the project with the * same name as the one specified in the request, will return the existing project_score @@ -23,40 +36,80 @@ interface ProjectScoreServiceAsync { */ suspend fun create( params: ProjectScoreCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore /** Get a project_score object by its id */ + suspend fun retrieve( + projectScoreId: String, + params: ProjectScoreRetrieveParams = ProjectScoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectScore = + retrieve(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: ProjectScoreRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + /** @see retrieve */ + suspend fun retrieve(projectScoreId: String, requestOptions: RequestOptions): ProjectScore = + retrieve(projectScoreId, ProjectScoreRetrieveParams.none(), requestOptions) + /** * Partially update a project_score object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + projectScoreId: String, + params: ProjectScoreUpdateParams = ProjectScoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectScore = + update(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see update */ suspend fun update( params: ProjectScoreUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + /** @see update */ + suspend fun update(projectScoreId: String, requestOptions: RequestOptions): ProjectScore = + update(projectScoreId, ProjectScoreUpdateParams.none(), requestOptions) + /** * List out all project_scores. The project_scores are sorted by creation date, with the most * recently-created project_scores coming first */ suspend fun list( - params: ProjectScoreListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ProjectScoreListParams = ProjectScoreListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScoreListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): ProjectScoreListPageAsync = + list(ProjectScoreListParams.none(), requestOptions) + /** Delete a project_score object by its id */ + suspend fun delete( + projectScoreId: String, + params: ProjectScoreDeleteParams = ProjectScoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectScore = + delete(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: ProjectScoreDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + /** @see delete */ + suspend fun delete(projectScoreId: String, requestOptions: RequestOptions): ProjectScore = + delete(projectScoreId, ProjectScoreDeleteParams.none(), requestOptions) + /** * Create or replace project_score. If there is an existing project_score in the project with * the same name as the one specified in the request, will replace the existing project_score @@ -64,6 +117,140 @@ interface ProjectScoreServiceAsync { */ suspend fun replace( params: ProjectScoreReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + + /** + * A view of [ProjectScoreServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): ProjectScoreServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project_score`, but is otherwise the same as + * [ProjectScoreServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: ProjectScoreCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project_score/{project_score_id}`, but is + * otherwise the same as [ProjectScoreServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + projectScoreId: String, + params: ProjectScoreRetrieveParams = ProjectScoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: ProjectScoreRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + projectScoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(projectScoreId, ProjectScoreRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/project_score/{project_score_id}`, but is + * otherwise the same as [ProjectScoreServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + projectScoreId: String, + params: ProjectScoreUpdateParams = ProjectScoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: ProjectScoreUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + projectScoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(projectScoreId, ProjectScoreUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/project_score`, but is otherwise the same as + * [ProjectScoreServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: ProjectScoreListParams = ProjectScoreListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list( + requestOptions: RequestOptions + ): HttpResponseFor = + list(ProjectScoreListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/project_score/{project_score_id}`, but is + * otherwise the same as [ProjectScoreServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + projectScoreId: String, + params: ProjectScoreDeleteParams = ProjectScoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: ProjectScoreDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + projectScoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(projectScoreId, ProjectScoreDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/project_score`, but is otherwise the same as + * [ProjectScoreServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: ProjectScoreReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsyncImpl.kt index 699cf6bd..696cc113 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsyncImpl.kt @@ -4,216 +4,275 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.ProjectScore import com.braintrustdata.api.models.ProjectScoreCreateParams import com.braintrustdata.api.models.ProjectScoreDeleteParams import com.braintrustdata.api.models.ProjectScoreListPageAsync +import com.braintrustdata.api.models.ProjectScoreListPageResponse import com.braintrustdata.api.models.ProjectScoreListParams import com.braintrustdata.api.models.ProjectScoreReplaceParams import com.braintrustdata.api.models.ProjectScoreRetrieveParams import com.braintrustdata.api.models.ProjectScoreUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class ProjectScoreServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : ProjectScoreServiceAsync { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new project_score. If there is an existing project_score in the project with the - * same name as the one specified in the request, will return the existing project_score - * unmodified - */ + +class ProjectScoreServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectScoreServiceAsync { + + private val withRawResponse: ProjectScoreServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ProjectScoreServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ProjectScoreServiceAsync = + ProjectScoreServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + override suspend fun create( params: ProjectScoreCreateParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_score") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): ProjectScore = + // post /v1/project_score + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: ProjectScoreRetrieveParams, + requestOptions: RequestOptions, + ): ProjectScore = + // get /v1/project_score/{project_score_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: ProjectScoreUpdateParams, + requestOptions: RequestOptions, + ): ProjectScore = + // patch /v1/project_score/{project_score_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: ProjectScoreListParams, + requestOptions: RequestOptions, + ): ProjectScoreListPageAsync = + // get /v1/project_score + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: ProjectScoreDeleteParams, + requestOptions: RequestOptions, + ): ProjectScore = + // delete /v1/project_score/{project_score_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace( + params: ProjectScoreReplaceParams, + requestOptions: RequestOptions, + ): ProjectScore = + // put /v1/project_score + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectScoreServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ProjectScoreServiceAsync.WithRawResponse = + ProjectScoreServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: ProjectScoreCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get a project_score object by its id */ - override suspend fun retrieve( - params: ProjectScoreRetrieveParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_score", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: ProjectScoreRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectScoreId", params.projectScoreId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update a project_score object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: ProjectScoreUpdateParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "project_score", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: ProjectScoreUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectScoreId", params.projectScoreId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all project_scores. The project_scores are sorted by creation date, with the most - * recently-created project_scores coming first - */ - override suspend fun list( - params: ProjectScoreListParams, - requestOptions: RequestOptions - ): ProjectScoreListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_score") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: ProjectScoreListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { ProjectScoreListPageAsync.of(this, params, it) } + .let { + ProjectScoreListPageAsync.builder() + .service(ProjectScoreServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete a project_score object by its id */ - override suspend fun delete( - params: ProjectScoreDeleteParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "project_score", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: ProjectScoreDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectScoreId", params.projectScoreId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace project_score. If there is an existing project_score in the project with - * the same name as the one specified in the request, will replace the existing project_score - * with the provided fields - */ - override suspend fun replace( - params: ProjectScoreReplaceParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "project_score") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun replace( + params: ProjectScoreReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsync.kt index 3aa98ff0..171d165d 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Project import com.braintrustdata.api.models.ProjectCreateParams import com.braintrustdata.api.models.ProjectDeleteParams @@ -13,9 +13,22 @@ import com.braintrustdata.api.models.ProjectListParams import com.braintrustdata.api.models.ProjectRetrieveParams import com.braintrustdata.api.models.ProjectUpdateParams import com.braintrustdata.api.services.async.projects.LogServiceAsync +import com.google.errorprone.annotations.MustBeClosed interface ProjectServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): ProjectServiceAsync + fun logs(): LogServiceAsync /** @@ -24,37 +37,195 @@ interface ProjectServiceAsync { */ suspend fun create( params: ProjectCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project /** Get a project object by its id */ + suspend fun retrieve( + projectId: String, + params: ProjectRetrieveParams = ProjectRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Project = retrieve(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: ProjectRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project + /** @see retrieve */ + suspend fun retrieve(projectId: String, requestOptions: RequestOptions): Project = + retrieve(projectId, ProjectRetrieveParams.none(), requestOptions) + /** * Partially update a project object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + projectId: String, + params: ProjectUpdateParams = ProjectUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Project = update(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see update */ suspend fun update( params: ProjectUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project + /** @see update */ + suspend fun update(projectId: String, requestOptions: RequestOptions): Project = + update(projectId, ProjectUpdateParams.none(), requestOptions) + /** * List out all projects. The projects are sorted by creation date, with the most * recently-created projects coming first */ suspend fun list( - params: ProjectListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ProjectListParams = ProjectListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): ProjectListPageAsync = + list(ProjectListParams.none(), requestOptions) + /** Delete a project object by its id */ + suspend fun delete( + projectId: String, + params: ProjectDeleteParams = ProjectDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Project = delete(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: ProjectDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project + + /** @see delete */ + suspend fun delete(projectId: String, requestOptions: RequestOptions): Project = + delete(projectId, ProjectDeleteParams.none(), requestOptions) + + /** + * A view of [ProjectServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): ProjectServiceAsync.WithRawResponse + + fun logs(): LogServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project`, but is otherwise the same as + * [ProjectServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: ProjectCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project/{project_id}`, but is otherwise the same + * as [ProjectServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + projectId: String, + params: ProjectRetrieveParams = ProjectRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: ProjectRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + projectId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(projectId, ProjectRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/project/{project_id}`, but is otherwise the + * same as [ProjectServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + projectId: String, + params: ProjectUpdateParams = ProjectUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: ProjectUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + projectId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = update(projectId, ProjectUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/project`, but is otherwise the same as + * [ProjectServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: ProjectListParams = ProjectListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ProjectListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/project/{project_id}`, but is otherwise the + * same as [ProjectServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + projectId: String, + params: ProjectDeleteParams = ProjectDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: ProjectDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + projectId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = delete(projectId, ProjectDeleteParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsyncImpl.kt index 9efa9ec1..f8f16170 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsyncImpl.kt @@ -4,187 +4,248 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Project import com.braintrustdata.api.models.ProjectCreateParams import com.braintrustdata.api.models.ProjectDeleteParams import com.braintrustdata.api.models.ProjectListPageAsync +import com.braintrustdata.api.models.ProjectListPageResponse import com.braintrustdata.api.models.ProjectListParams import com.braintrustdata.api.models.ProjectRetrieveParams import com.braintrustdata.api.models.ProjectUpdateParams import com.braintrustdata.api.services.async.projects.LogServiceAsync import com.braintrustdata.api.services.async.projects.LogServiceAsyncImpl -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ProjectServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : ProjectServiceAsync { +class ProjectServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ProjectServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } private val logs: LogServiceAsync by lazy { LogServiceAsyncImpl(clientOptions) } - override fun logs(): LogServiceAsync = logs + override fun withRawResponse(): ProjectServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ProjectServiceAsync = + ProjectServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun logs(): LogServiceAsync = logs - /** - * Create a new project. If there is an existing project with the same name as the one specified - * in the request, will return the existing project unmodified - */ override suspend fun create( params: ProjectCreateParams, - requestOptions: RequestOptions - ): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } - } + requestOptions: RequestOptions, + ): Project = + // post /v1/project + withRawResponse().create(params, requestOptions).parse() - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get a project object by its id */ override suspend fun retrieve( params: ProjectRetrieveParams, - requestOptions: RequestOptions - ): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } - } + requestOptions: RequestOptions, + ): Project = + // get /v1/project/{project_id} + withRawResponse().retrieve(params, requestOptions).parse() - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a project object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ override suspend fun update( params: ProjectUpdateParams, - requestOptions: RequestOptions - ): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "project", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Project = + // patch /v1/project/{project_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: ProjectListParams, + requestOptions: RequestOptions, + ): ProjectListPageAsync = + // get /v1/project + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: ProjectDeleteParams, + requestOptions: RequestOptions, + ): Project = + // delete /v1/project/{project_id} + withRawResponse().delete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + private val logs: LogServiceAsync.WithRawResponse by lazy { + LogServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ProjectServiceAsync.WithRawResponse = + ProjectServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + override fun logs(): LogServiceAsync.WithRawResponse = logs + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: ProjectCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: ProjectRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } - /** - * List out all projects. The projects are sorted by creation date, with the most - * recently-created projects coming first - */ - override suspend fun list( - params: ProjectListParams, - requestOptions: RequestOptions - ): ProjectListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun update( + params: ProjectUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { ProjectListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun list( + params: ProjectListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + ProjectListPageAsync.builder() + .service(ProjectServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } + } - /** Delete a project object by its id */ - override suspend fun delete( - params: ProjectDeleteParams, - requestOptions: RequestOptions - ): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "project", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun delete( + params: ProjectDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsync.kt index 85c4f073..44eead34 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.ProjectTag import com.braintrustdata.api.models.ProjectTagCreateParams import com.braintrustdata.api.models.ProjectTagDeleteParams @@ -13,49 +13,99 @@ import com.braintrustdata.api.models.ProjectTagListParams import com.braintrustdata.api.models.ProjectTagReplaceParams import com.braintrustdata.api.models.ProjectTagRetrieveParams import com.braintrustdata.api.models.ProjectTagUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface ProjectTagServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): ProjectTagServiceAsync + /** * Create a new project_tag. If there is an existing project_tag in the project with the same * name as the one specified in the request, will return the existing project_tag unmodified */ suspend fun create( params: ProjectTagCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag /** Get a project_tag object by its id */ + suspend fun retrieve( + projectTagId: String, + params: ProjectTagRetrieveParams = ProjectTagRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectTag = retrieve(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: ProjectTagRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + /** @see retrieve */ + suspend fun retrieve(projectTagId: String, requestOptions: RequestOptions): ProjectTag = + retrieve(projectTagId, ProjectTagRetrieveParams.none(), requestOptions) + /** * Partially update a project_tag object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + projectTagId: String, + params: ProjectTagUpdateParams = ProjectTagUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectTag = update(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see update */ suspend fun update( params: ProjectTagUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + /** @see update */ + suspend fun update(projectTagId: String, requestOptions: RequestOptions): ProjectTag = + update(projectTagId, ProjectTagUpdateParams.none(), requestOptions) + /** * List out all project_tags. The project_tags are sorted by creation date, with the most * recently-created project_tags coming first */ suspend fun list( - params: ProjectTagListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ProjectTagListParams = ProjectTagListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTagListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): ProjectTagListPageAsync = + list(ProjectTagListParams.none(), requestOptions) + /** Delete a project_tag object by its id */ + suspend fun delete( + projectTagId: String, + params: ProjectTagDeleteParams = ProjectTagDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectTag = delete(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: ProjectTagDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + /** @see delete */ + suspend fun delete(projectTagId: String, requestOptions: RequestOptions): ProjectTag = + delete(projectTagId, ProjectTagDeleteParams.none(), requestOptions) + /** * Create or replace project_tag. If there is an existing project_tag in the project with the * same name as the one specified in the request, will replace the existing project_tag with the @@ -63,6 +113,138 @@ interface ProjectTagServiceAsync { */ suspend fun replace( params: ProjectTagReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + + /** + * A view of [ProjectTagServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): ProjectTagServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project_tag`, but is otherwise the same as + * [ProjectTagServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: ProjectTagCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project_tag/{project_tag_id}`, but is otherwise + * the same as [ProjectTagServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + projectTagId: String, + params: ProjectTagRetrieveParams = ProjectTagRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: ProjectTagRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + projectTagId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(projectTagId, ProjectTagRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/project_tag/{project_tag_id}`, but is + * otherwise the same as [ProjectTagServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + projectTagId: String, + params: ProjectTagUpdateParams = ProjectTagUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: ProjectTagUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + projectTagId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(projectTagId, ProjectTagUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/project_tag`, but is otherwise the same as + * [ProjectTagServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: ProjectTagListParams = ProjectTagListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ProjectTagListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/project_tag/{project_tag_id}`, but is + * otherwise the same as [ProjectTagServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + projectTagId: String, + params: ProjectTagDeleteParams = ProjectTagDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: ProjectTagDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + projectTagId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(projectTagId, ProjectTagDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/project_tag`, but is otherwise the same as + * [ProjectTagServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: ProjectTagReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsyncImpl.kt index 617eb650..1094c439 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsyncImpl.kt @@ -4,215 +4,275 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.ProjectTag import com.braintrustdata.api.models.ProjectTagCreateParams import com.braintrustdata.api.models.ProjectTagDeleteParams import com.braintrustdata.api.models.ProjectTagListPageAsync +import com.braintrustdata.api.models.ProjectTagListPageResponse import com.braintrustdata.api.models.ProjectTagListParams import com.braintrustdata.api.models.ProjectTagReplaceParams import com.braintrustdata.api.models.ProjectTagRetrieveParams import com.braintrustdata.api.models.ProjectTagUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ProjectTagServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : ProjectTagServiceAsync { +class ProjectTagServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectTagServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ProjectTagServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ProjectTagServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ProjectTagServiceAsync = + ProjectTagServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new project_tag. If there is an existing project_tag in the project with the same - * name as the one specified in the request, will return the existing project_tag unmodified - */ override suspend fun create( params: ProjectTagCreateParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_tag") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): ProjectTag = + // post /v1/project_tag + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: ProjectTagRetrieveParams, + requestOptions: RequestOptions, + ): ProjectTag = + // get /v1/project_tag/{project_tag_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: ProjectTagUpdateParams, + requestOptions: RequestOptions, + ): ProjectTag = + // patch /v1/project_tag/{project_tag_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: ProjectTagListParams, + requestOptions: RequestOptions, + ): ProjectTagListPageAsync = + // get /v1/project_tag + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: ProjectTagDeleteParams, + requestOptions: RequestOptions, + ): ProjectTag = + // delete /v1/project_tag/{project_tag_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace( + params: ProjectTagReplaceParams, + requestOptions: RequestOptions, + ): ProjectTag = + // put /v1/project_tag + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectTagServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ProjectTagServiceAsync.WithRawResponse = + ProjectTagServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: ProjectTagCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get a project_tag object by its id */ - override suspend fun retrieve( - params: ProjectTagRetrieveParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_tag", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: ProjectTagRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectTagId", params.projectTagId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update a project_tag object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: ProjectTagUpdateParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "project_tag", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: ProjectTagUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectTagId", params.projectTagId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all project_tags. The project_tags are sorted by creation date, with the most - * recently-created project_tags coming first - */ - override suspend fun list( - params: ProjectTagListParams, - requestOptions: RequestOptions - ): ProjectTagListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_tag") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: ProjectTagListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + ProjectTagListPageAsync.builder() + .service(ProjectTagServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { ProjectTagListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete a project_tag object by its id */ - override suspend fun delete( - params: ProjectTagDeleteParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "project_tag", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: ProjectTagDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectTagId", params.projectTagId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace project_tag. If there is an existing project_tag in the project with the - * same name as the one specified in the request, will replace the existing project_tag with the - * provided fields - */ - override suspend fun replace( - params: ProjectTagReplaceParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "project_tag") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun replace( + params: ProjectTagReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsync.kt index 94342356..2e2fbcc4 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Prompt import com.braintrustdata.api.models.PromptCreateParams import com.braintrustdata.api.models.PromptDeleteParams @@ -13,55 +13,233 @@ import com.braintrustdata.api.models.PromptListParams import com.braintrustdata.api.models.PromptReplaceParams import com.braintrustdata.api.models.PromptRetrieveParams import com.braintrustdata.api.models.PromptUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface PromptServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): PromptServiceAsync + /** * Create a new prompt. If there is an existing prompt in the project with the same slug as the * one specified in the request, will return the existing prompt unmodified */ suspend fun create( params: PromptCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt /** Get a prompt object by its id */ + suspend fun retrieve( + promptId: String, + params: PromptRetrieveParams = PromptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Prompt = retrieve(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: PromptRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + /** @see retrieve */ + suspend fun retrieve(promptId: String, requestOptions: RequestOptions): Prompt = + retrieve(promptId, PromptRetrieveParams.none(), requestOptions) + /** * Partially update a prompt object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + suspend fun update( + promptId: String, + params: PromptUpdateParams = PromptUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Prompt = update(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see update */ suspend fun update( params: PromptUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + /** @see update */ + suspend fun update(promptId: String, requestOptions: RequestOptions): Prompt = + update(promptId, PromptUpdateParams.none(), requestOptions) + /** * List out all prompts. The prompts are sorted by creation date, with the most recently-created * prompts coming first */ suspend fun list( - params: PromptListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: PromptListParams = PromptListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): PromptListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): PromptListPageAsync = + list(PromptListParams.none(), requestOptions) + /** Delete a prompt object by its id */ + suspend fun delete( + promptId: String, + params: PromptDeleteParams = PromptDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Prompt = delete(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: PromptDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + /** @see delete */ + suspend fun delete(promptId: String, requestOptions: RequestOptions): Prompt = + delete(promptId, PromptDeleteParams.none(), requestOptions) + /** * Create or replace prompt. If there is an existing prompt in the project with the same slug as * the one specified in the request, will replace the existing prompt with the provided fields */ suspend fun replace( params: PromptReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + + /** + * A view of [PromptServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): PromptServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/prompt`, but is otherwise the same as + * [PromptServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: PromptCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/prompt/{prompt_id}`, but is otherwise the same + * as [PromptServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + promptId: String, + params: PromptRetrieveParams = PromptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: PromptRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + promptId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = retrieve(promptId, PromptRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/prompt/{prompt_id}`, but is otherwise the same + * as [PromptServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + promptId: String, + params: PromptUpdateParams = PromptUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: PromptUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + promptId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = update(promptId, PromptUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/prompt`, but is otherwise the same as + * [PromptServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: PromptListParams = PromptListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(PromptListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/prompt/{prompt_id}`, but is otherwise the + * same as [PromptServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + promptId: String, + params: PromptDeleteParams = PromptDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: PromptDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + promptId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = delete(promptId, PromptDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/prompt`, but is otherwise the same as + * [PromptServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: PromptReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsyncImpl.kt index c77cd3e3..cc0d36ff 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/PromptServiceAsyncImpl.kt @@ -4,214 +4,270 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Prompt import com.braintrustdata.api.models.PromptCreateParams import com.braintrustdata.api.models.PromptDeleteParams import com.braintrustdata.api.models.PromptListPageAsync +import com.braintrustdata.api.models.PromptListPageResponse import com.braintrustdata.api.models.PromptListParams import com.braintrustdata.api.models.PromptReplaceParams import com.braintrustdata.api.models.PromptRetrieveParams import com.braintrustdata.api.models.PromptUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class PromptServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : PromptServiceAsync { +class PromptServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + PromptServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: PromptServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): PromptServiceAsync.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): PromptServiceAsync = + PromptServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new prompt. If there is an existing prompt in the project with the same slug as the - * one specified in the request, will return the existing prompt unmodified - */ override suspend fun create( params: PromptCreateParams, - requestOptions: RequestOptions - ): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "prompt") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Prompt = + // post /v1/prompt + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: PromptRetrieveParams, + requestOptions: RequestOptions, + ): Prompt = + // get /v1/prompt/{prompt_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: PromptUpdateParams, + requestOptions: RequestOptions, + ): Prompt = + // patch /v1/prompt/{prompt_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: PromptListParams, + requestOptions: RequestOptions, + ): PromptListPageAsync = + // get /v1/prompt + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: PromptDeleteParams, + requestOptions: RequestOptions, + ): Prompt = + // delete /v1/prompt/{prompt_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace( + params: PromptReplaceParams, + requestOptions: RequestOptions, + ): Prompt = + // put /v1/prompt + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + PromptServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): PromptServiceAsync.WithRawResponse = + PromptServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: PromptCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Get a prompt object by its id */ - override suspend fun retrieve( - params: PromptRetrieveParams, - requestOptions: RequestOptions - ): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "prompt", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun retrieve( + params: PromptRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("promptId", params.promptId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * Partially update a prompt object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override suspend fun update( - params: PromptUpdateParams, - requestOptions: RequestOptions - ): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "prompt", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: PromptUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("promptId", params.promptId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all prompts. The prompts are sorted by creation date, with the most recently-created - * prompts coming first - */ - override suspend fun list( - params: PromptListParams, - requestOptions: RequestOptions - ): PromptListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "prompt") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: PromptListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + PromptListPageAsync.builder() + .service(PromptServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { PromptListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Delete a prompt object by its id */ - override suspend fun delete( - params: PromptDeleteParams, - requestOptions: RequestOptions - ): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "prompt", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun delete( + params: PromptDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("promptId", params.promptId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace prompt. If there is an existing prompt in the project with the same slug as - * the one specified in the request, will replace the existing prompt with the provided fields - */ - override suspend fun replace( - params: PromptReplaceParams, - requestOptions: RequestOptions - ): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "prompt") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun replace( + params: PromptReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsync.kt index e5f7849c..82f1a9eb 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Role import com.braintrustdata.api.models.RoleCreateParams import com.braintrustdata.api.models.RoleDeleteParams @@ -13,55 +13,223 @@ import com.braintrustdata.api.models.RoleListParams import com.braintrustdata.api.models.RoleReplaceParams import com.braintrustdata.api.models.RoleRetrieveParams import com.braintrustdata.api.models.RoleUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface RoleServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): RoleServiceAsync + /** * Create a new role. If there is an existing role with the same name as the one specified in * the request, will return the existing role unmodified */ suspend fun create( params: RoleCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role /** Get a role object by its id */ + suspend fun retrieve( + roleId: String, + params: RoleRetrieveParams = RoleRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Role = retrieve(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: RoleRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + /** @see retrieve */ + suspend fun retrieve(roleId: String, requestOptions: RequestOptions): Role = + retrieve(roleId, RoleRetrieveParams.none(), requestOptions) + /** * Partially update a role object. Specify the fields to update in the payload. Any object-type * fields will be deep-merged with existing content. Currently we do not support removing fields * or setting them to null. */ + suspend fun update( + roleId: String, + params: RoleUpdateParams = RoleUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Role = update(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see update */ suspend fun update( params: RoleUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + /** @see update */ + suspend fun update(roleId: String, requestOptions: RequestOptions): Role = + update(roleId, RoleUpdateParams.none(), requestOptions) + /** * List out all roles. The roles are sorted by creation date, with the most recently-created * roles coming first */ suspend fun list( - params: RoleListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: RoleListParams = RoleListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): RoleListPageAsync + /** @see list */ + suspend fun list(requestOptions: RequestOptions): RoleListPageAsync = + list(RoleListParams.none(), requestOptions) + /** Delete a role object by its id */ + suspend fun delete( + roleId: String, + params: RoleDeleteParams = RoleDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Role = delete(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see delete */ suspend fun delete( params: RoleDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + /** @see delete */ + suspend fun delete(roleId: String, requestOptions: RequestOptions): Role = + delete(roleId, RoleDeleteParams.none(), requestOptions) + /** * Create or replace role. If there is an existing role with the same name as the one specified * in the request, will replace the existing role with the provided fields */ suspend fun replace( params: RoleReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + + /** A view of [RoleServiceAsync] 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: (ClientOptions.Builder) -> Unit): RoleServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/role`, but is otherwise the same as + * [RoleServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: RoleCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/role/{role_id}`, but is otherwise the same as + * [RoleServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + roleId: String, + params: RoleRetrieveParams = RoleRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: RoleRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + roleId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = retrieve(roleId, RoleRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/role/{role_id}`, but is otherwise the same as + * [RoleServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + roleId: String, + params: RoleUpdateParams = RoleUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = update(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: RoleUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update(roleId: String, requestOptions: RequestOptions): HttpResponseFor = + update(roleId, RoleUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/role`, but is otherwise the same as + * [RoleServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: RoleListParams = RoleListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(RoleListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/role/{role_id}`, but is otherwise the same as + * [RoleServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + roleId: String, + params: RoleDeleteParams = RoleDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = delete(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: RoleDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete(roleId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(roleId, RoleDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/role`, but is otherwise the same as + * [RoleServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: RoleReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsyncImpl.kt index 321be90e..165a8281 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/RoleServiceAsyncImpl.kt @@ -4,202 +4,258 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.Role import com.braintrustdata.api.models.RoleCreateParams import com.braintrustdata.api.models.RoleDeleteParams import com.braintrustdata.api.models.RoleListPageAsync +import com.braintrustdata.api.models.RoleListPageResponse import com.braintrustdata.api.models.RoleListParams import com.braintrustdata.api.models.RoleReplaceParams import com.braintrustdata.api.models.RoleRetrieveParams import com.braintrustdata.api.models.RoleUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class RoleServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : RoleServiceAsync { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new role. If there is an existing role with the same name as the one specified in - * the request, will return the existing role unmodified - */ - override suspend fun create(params: RoleCreateParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "role") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } + +class RoleServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + RoleServiceAsync { + + private val withRawResponse: RoleServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withRawResponse(): RoleServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): RoleServiceAsync = + RoleServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + + override suspend fun create(params: RoleCreateParams, requestOptions: RequestOptions): Role = + // post /v1/role + withRawResponse().create(params, requestOptions).parse() - /** Get a role object by its id */ override suspend fun retrieve( params: RoleRetrieveParams, - requestOptions: RequestOptions - ): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "role", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Role = + // get /v1/role/{role_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update(params: RoleUpdateParams, requestOptions: RequestOptions): Role = + // patch /v1/role/{role_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: RoleListParams, + requestOptions: RequestOptions, + ): RoleListPageAsync = + // get /v1/role + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete(params: RoleDeleteParams, requestOptions: RequestOptions): Role = + // delete /v1/role/{role_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace(params: RoleReplaceParams, requestOptions: RequestOptions): Role = + // put /v1/role + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + RoleServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): RoleServiceAsync.WithRawResponse = + RoleServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: RoleCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a role object. Specify the fields to update in the payload. Any object-type - * fields will be deep-merged with existing content. Currently we do not support removing fields - * or setting them to null. - */ - override suspend fun update(params: RoleUpdateParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "role", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: RoleRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("roleId", params.roleId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * List out all roles. The roles are sorted by creation date, with the most recently-created - * roles coming first - */ - override suspend fun list( - params: RoleListParams, - requestOptions: RequestOptions - ): RoleListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "role") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: RoleUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("roleId", params.roleId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { RoleListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a role object by its id */ - override suspend fun delete(params: RoleDeleteParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "role", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun list( + params: RoleListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + .let { + RoleListPageAsync.builder() + .service(RoleServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace role. If there is an existing role with the same name as the one specified - * in the request, will replace the existing role with the provided fields - */ - override suspend fun replace(params: RoleReplaceParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "role") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun delete( + params: RoleDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("roleId", params.roleId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun replace( + params: RoleReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsync.kt new file mode 100644 index 00000000..4c55391d --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsync.kt @@ -0,0 +1,249 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.models.SpanIFrame +import com.braintrustdata.api.models.SpanIframeCreateParams +import com.braintrustdata.api.models.SpanIframeDeleteParams +import com.braintrustdata.api.models.SpanIframeListPageAsync +import com.braintrustdata.api.models.SpanIframeListParams +import com.braintrustdata.api.models.SpanIframeReplaceParams +import com.braintrustdata.api.models.SpanIframeRetrieveParams +import com.braintrustdata.api.models.SpanIframeUpdateParams +import com.google.errorprone.annotations.MustBeClosed + +interface SpanIframeServiceAsync { + + /** + * 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: (ClientOptions.Builder) -> Unit): SpanIframeServiceAsync + + /** + * Create a new span_iframe. If there is an existing span_iframe with the same name as the one + * specified in the request, will return the existing span_iframe unmodified + */ + suspend fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** Get a span_iframe object by its id */ + suspend fun retrieve( + spanIframeId: String, + params: SpanIframeRetrieveParams = SpanIframeRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame = retrieve(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see retrieve */ + suspend fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** @see retrieve */ + suspend fun retrieve(spanIframeId: String, requestOptions: RequestOptions): SpanIFrame = + retrieve(spanIframeId, SpanIframeRetrieveParams.none(), requestOptions) + + /** + * Partially update a span_iframe object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ + suspend fun update( + spanIframeId: String, + params: SpanIframeUpdateParams = SpanIframeUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame = update(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see update */ + suspend fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** @see update */ + suspend fun update(spanIframeId: String, requestOptions: RequestOptions): SpanIFrame = + update(spanIframeId, SpanIframeUpdateParams.none(), requestOptions) + + /** + * List out all span_iframes. The span_iframes are sorted by creation date, with the most + * recently-created span_iframes coming first + */ + suspend fun list( + params: SpanIframeListParams = SpanIframeListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIframeListPageAsync + + /** @see list */ + suspend fun list(requestOptions: RequestOptions): SpanIframeListPageAsync = + list(SpanIframeListParams.none(), requestOptions) + + /** Delete a span_iframe object by its id */ + suspend fun delete( + spanIframeId: String, + params: SpanIframeDeleteParams = SpanIframeDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame = delete(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see delete */ + suspend fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** @see delete */ + suspend fun delete(spanIframeId: String, requestOptions: RequestOptions): SpanIFrame = + delete(spanIframeId, SpanIframeDeleteParams.none(), requestOptions) + + /** + * Create or replace span_iframe. If there is an existing span_iframe with the same name as the + * one specified in the request, will replace the existing span_iframe with the provided fields + */ + suspend fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** + * A view of [SpanIframeServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): SpanIframeServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/span_iframe`, but is otherwise the same as + * [SpanIframeServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/span_iframe/{span_iframe_id}`, but is otherwise + * the same as [SpanIframeServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + spanIframeId: String, + params: SpanIframeRetrieveParams = SpanIframeRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + spanIframeId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(spanIframeId, SpanIframeRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/span_iframe/{span_iframe_id}`, but is + * otherwise the same as [SpanIframeServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + spanIframeId: String, + params: SpanIframeUpdateParams = SpanIframeUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + spanIframeId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(spanIframeId, SpanIframeUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/span_iframe`, but is otherwise the same as + * [SpanIframeServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: SpanIframeListParams = SpanIframeListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(SpanIframeListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/span_iframe/{span_iframe_id}`, but is + * otherwise the same as [SpanIframeServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + spanIframeId: String, + params: SpanIframeDeleteParams = SpanIframeDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + suspend fun delete( + spanIframeId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(spanIframeId, SpanIframeDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/span_iframe`, but is otherwise the same as + * [SpanIframeServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsyncImpl.kt new file mode 100644 index 00000000..9db28954 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsyncImpl.kt @@ -0,0 +1,278 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler +import com.braintrustdata.api.core.http.HttpMethod +import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse +import com.braintrustdata.api.core.http.HttpResponse.Handler +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync +import com.braintrustdata.api.models.SpanIFrame +import com.braintrustdata.api.models.SpanIframeCreateParams +import com.braintrustdata.api.models.SpanIframeDeleteParams +import com.braintrustdata.api.models.SpanIframeListPageAsync +import com.braintrustdata.api.models.SpanIframeListPageResponse +import com.braintrustdata.api.models.SpanIframeListParams +import com.braintrustdata.api.models.SpanIframeReplaceParams +import com.braintrustdata.api.models.SpanIframeRetrieveParams +import com.braintrustdata.api.models.SpanIframeUpdateParams + +class SpanIframeServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + SpanIframeServiceAsync { + + private val withRawResponse: SpanIframeServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): SpanIframeServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): SpanIframeServiceAsync = + SpanIframeServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + + override suspend fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // post /v1/span_iframe + withRawResponse().create(params, requestOptions).parse() + + override suspend fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // get /v1/span_iframe/{span_iframe_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // patch /v1/span_iframe/{span_iframe_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: SpanIframeListParams, + requestOptions: RequestOptions, + ): SpanIframeListPageAsync = + // get /v1/span_iframe + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // delete /v1/span_iframe/{span_iframe_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // put /v1/span_iframe + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + SpanIframeServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): SpanIframeServiceAsync.WithRawResponse = + SpanIframeServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("spanIframeId", params.spanIframeId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("spanIframeId", params.spanIframeId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun list( + params: SpanIframeListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + SpanIframeListPageAsync.builder() + .service(SpanIframeServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } + } + + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("spanIframeId", params.spanIframeId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe", params._pathParam(0)) + .apply { params._body()?.let { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsync.kt index 3df67acd..f2eb0ea8 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsync.kt @@ -1,17 +1,64 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.TopLevelHelloWorldParams +import com.google.errorprone.annotations.MustBeClosed interface TopLevelServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): TopLevelServiceAsync + /** Default endpoint. Simply replies with 'Hello, World!'. Authorization is not required */ suspend fun helloWorld( - params: TopLevelHelloWorldParams, - requestOptions: RequestOptions = RequestOptions.none() + params: TopLevelHelloWorldParams = TopLevelHelloWorldParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): String + + /** @see helloWorld */ + suspend fun helloWorld(requestOptions: RequestOptions): String = + helloWorld(TopLevelHelloWorldParams.none(), requestOptions) + + /** + * A view of [TopLevelServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): TopLevelServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `get /v1`, but is otherwise the same as + * [TopLevelServiceAsync.helloWorld]. + */ + @MustBeClosed + suspend fun helloWorld( + params: TopLevelHelloWorldParams = TopLevelHelloWorldParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see helloWorld */ + @MustBeClosed + suspend fun helloWorld(requestOptions: RequestOptions): HttpResponseFor = + helloWorld(TopLevelHelloWorldParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsyncImpl.kt index a6da8c44..ad98767b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsyncImpl.kt @@ -4,40 +4,68 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.stringHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.TopLevelHelloWorldParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.stringHandler -import com.braintrustdata.api.services.withErrorHandler -class TopLevelServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : TopLevelServiceAsync { +class TopLevelServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + TopLevelServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: TopLevelServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): TopLevelServiceAsync.WithRawResponse = withRawResponse - private val helloWorldHandler: Handler = stringHandler().withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): TopLevelServiceAsync = + TopLevelServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** Default endpoint. Simply replies with 'Hello, World!'. Authorization is not required */ override suspend fun helloWorld( params: TopLevelHelloWorldParams, - requestOptions: RequestOptions - ): String { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response.use { helloWorldHandler.handle(it) } + requestOptions: RequestOptions, + ): String = + // get /v1 + withRawResponse().helloWorld(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + TopLevelServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): TopLevelServiceAsync.WithRawResponse = + TopLevelServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val helloWorldHandler: Handler = stringHandler() + + override suspend fun helloWorld( + params: TopLevelHelloWorldParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response.use { helloWorldHandler.handle(it) } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsync.kt index 9da26437..a4f7a567 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsync.kt @@ -1,29 +1,109 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.User import com.braintrustdata.api.models.UserListPageAsync import com.braintrustdata.api.models.UserListParams import com.braintrustdata.api.models.UserRetrieveParams +import com.google.errorprone.annotations.MustBeClosed interface UserServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): UserServiceAsync + /** Get a user object by its id */ + suspend fun retrieve( + userId: String, + params: UserRetrieveParams = UserRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): User = retrieve(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see retrieve */ suspend fun retrieve( params: UserRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): User + /** @see retrieve */ + suspend fun retrieve(userId: String, requestOptions: RequestOptions): User = + retrieve(userId, UserRetrieveParams.none(), requestOptions) + /** * List out all users. The users are sorted by creation date, with the most recently-created * users coming first */ suspend fun list( - params: UserListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: UserListParams = UserListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): UserListPageAsync + + /** @see list */ + suspend fun list(requestOptions: RequestOptions): UserListPageAsync = + list(UserListParams.none(), requestOptions) + + /** A view of [UserServiceAsync] 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: (ClientOptions.Builder) -> Unit): UserServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `get /v1/user/{user_id}`, but is otherwise the same as + * [UserServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + userId: String, + params: UserRetrieveParams = UserRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: UserRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + userId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = retrieve(userId, UserRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/user`, but is otherwise the same as + * [UserServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: UserListParams = UserListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + suspend fun list(requestOptions: RequestOptions): HttpResponseFor = + list(UserListParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsyncImpl.kt index 0c4276d2..f415793a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/UserServiceAsyncImpl.kt @@ -4,83 +4,123 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.User import com.braintrustdata.api.models.UserListPageAsync +import com.braintrustdata.api.models.UserListPageResponse import com.braintrustdata.api.models.UserListParams import com.braintrustdata.api.models.UserRetrieveParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class UserServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : UserServiceAsync { +class UserServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + UserServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: UserServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): UserServiceAsync.WithRawResponse = withRawResponse - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): UserServiceAsync = + UserServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** Get a user object by its id */ override suspend fun retrieve( params: UserRetrieveParams, - requestOptions: RequestOptions - ): User { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "user", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): User = + // get /v1/user/{user_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun list( + params: UserListParams, + requestOptions: RequestOptions, + ): UserListPageAsync = + // get /v1/user + withRawResponse().list(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + UserServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): UserServiceAsync.WithRawResponse = + UserServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: UserRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "user", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all users. The users are sorted by creation date, with the most recently-created - * users coming first - */ - override suspend fun list( - params: UserListParams, - requestOptions: RequestOptions - ): UserListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "user") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun list( + params: UserListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "user") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + UserListPageAsync.builder() + .service(UserServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { UserListPageAsync.of(this, params, it) } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsync.kt index dd1491b4..e305aed2 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.View import com.braintrustdata.api.models.ViewCreateParams import com.braintrustdata.api.models.ViewDeleteParams @@ -13,22 +13,42 @@ import com.braintrustdata.api.models.ViewListParams import com.braintrustdata.api.models.ViewReplaceParams import com.braintrustdata.api.models.ViewRetrieveParams import com.braintrustdata.api.models.ViewUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface ViewServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): ViewServiceAsync + /** * Create a new view. If there is an existing view with the same name as the one specified in * the request, will return the existing view unmodified */ suspend fun create( params: ViewCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): View /** Get a view object by its id */ suspend fun retrieve( + viewId: String, params: ViewRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): View = retrieve(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see retrieve */ + suspend fun retrieve( + params: ViewRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), ): View /** @@ -37,8 +57,15 @@ interface ViewServiceAsync { * or setting them to null. */ suspend fun update( + viewId: String, params: ViewUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): View = update(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see update */ + suspend fun update( + params: ViewUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), ): View /** @@ -47,13 +74,20 @@ interface ViewServiceAsync { */ suspend fun list( params: ViewListParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ViewListPageAsync /** Delete a view object by its id */ suspend fun delete( + viewId: String, params: ViewDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): View = delete(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see delete */ + suspend fun delete( + params: ViewDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), ): View /** @@ -62,6 +96,102 @@ interface ViewServiceAsync { */ suspend fun replace( params: ViewReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): View + + /** A view of [ViewServiceAsync] 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: (ClientOptions.Builder) -> Unit): ViewServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/view`, but is otherwise the same as + * [ViewServiceAsync.create]. + */ + @MustBeClosed + suspend fun create( + params: ViewCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/view/{view_id}`, but is otherwise the same as + * [ViewServiceAsync.retrieve]. + */ + @MustBeClosed + suspend fun retrieve( + viewId: String, + params: ViewRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + suspend fun retrieve( + params: ViewRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `patch /v1/view/{view_id}`, but is otherwise the same as + * [ViewServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + viewId: String, + params: ViewUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = update(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + suspend fun update( + params: ViewUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/view`, but is otherwise the same as + * [ViewServiceAsync.list]. + */ + @MustBeClosed + suspend fun list( + params: ViewListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `delete /v1/view/{view_id}`, but is otherwise the same as + * [ViewServiceAsync.delete]. + */ + @MustBeClosed + suspend fun delete( + viewId: String, + params: ViewDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = delete(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + suspend fun delete( + params: ViewDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `put /v1/view`, but is otherwise the same as + * [ViewServiceAsync.replace]. + */ + @MustBeClosed + suspend fun replace( + params: ViewReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsyncImpl.kt index c39c4bd4..ceb27442 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/ViewServiceAsyncImpl.kt @@ -4,202 +4,258 @@ package com.braintrustdata.api.services.async import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.View import com.braintrustdata.api.models.ViewCreateParams import com.braintrustdata.api.models.ViewDeleteParams import com.braintrustdata.api.models.ViewListPageAsync +import com.braintrustdata.api.models.ViewListPageResponse import com.braintrustdata.api.models.ViewListParams import com.braintrustdata.api.models.ViewReplaceParams import com.braintrustdata.api.models.ViewRetrieveParams import com.braintrustdata.api.models.ViewUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class ViewServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : ViewServiceAsync { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new view. If there is an existing view with the same name as the one specified in - * the request, will return the existing view unmodified - */ - override suspend fun create(params: ViewCreateParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "view") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } + +class ViewServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + ViewServiceAsync { + + private val withRawResponse: ViewServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withRawResponse(): ViewServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ViewServiceAsync = + ViewServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) + + override suspend fun create(params: ViewCreateParams, requestOptions: RequestOptions): View = + // post /v1/view + withRawResponse().create(params, requestOptions).parse() - /** Get a view object by its id */ override suspend fun retrieve( params: ViewRetrieveParams, - requestOptions: RequestOptions - ): View { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "view", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): View = + // get /v1/view/{view_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override suspend fun update(params: ViewUpdateParams, requestOptions: RequestOptions): View = + // patch /v1/view/{view_id} + withRawResponse().update(params, requestOptions).parse() + + override suspend fun list( + params: ViewListParams, + requestOptions: RequestOptions, + ): ViewListPageAsync = + // get /v1/view + withRawResponse().list(params, requestOptions).parse() + + override suspend fun delete(params: ViewDeleteParams, requestOptions: RequestOptions): View = + // delete /v1/view/{view_id} + withRawResponse().delete(params, requestOptions).parse() + + override suspend fun replace(params: ViewReplaceParams, requestOptions: RequestOptions): View = + // put /v1/view + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ViewServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ViewServiceAsync.WithRawResponse = + ViewServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun create( + params: ViewCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a view object. Specify the fields to update in the payload. Any object-type - * fields will be deep-merged with existing content. Currently we do not support removing fields - * or setting them to null. - */ - override suspend fun update(params: ViewUpdateParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "view", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun retrieve( + params: ViewRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("viewId", params.viewId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** - * List out all views. The views are sorted by creation date, with the most recently-created - * views coming first - */ - override suspend fun list( - params: ViewListParams, - requestOptions: RequestOptions - ): ViewListPageAsync { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "view") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun update( + params: ViewUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("viewId", params.viewId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { ViewListPageAsync.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a view object by its id */ - override suspend fun delete(params: ViewDeleteParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "view", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun list( + params: ViewListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + .let { + ViewListPageAsync.builder() + .service(ViewServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace view. If there is an existing view with the same name as the one specified - * in the request, will replace the existing view with the provided fields - */ - override suspend fun replace(params: ViewReplaceParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "view") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun delete( + params: ViewDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("viewId", params.viewId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view", params._pathParam(0)) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override suspend fun replace( + params: ViewReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsync.kt index 2b36ec9c..3fdb52cf 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsync.kt @@ -1,18 +1,67 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async.organizations +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.OrganizationMemberUpdateParams import com.braintrustdata.api.models.PatchOrganizationMembersOutput +import com.google.errorprone.annotations.MustBeClosed interface MemberServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): MemberServiceAsync + /** Modify organization membership */ suspend fun update( - params: OrganizationMemberUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + params: OrganizationMemberUpdateParams = OrganizationMemberUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): PatchOrganizationMembersOutput + + /** @see update */ + suspend fun update(requestOptions: RequestOptions): PatchOrganizationMembersOutput = + update(OrganizationMemberUpdateParams.none(), requestOptions) + + /** + * A view of [MemberServiceAsync] 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: (ClientOptions.Builder) -> Unit + ): MemberServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `patch /v1/organization/members`, but is otherwise the + * same as [MemberServiceAsync.update]. + */ + @MustBeClosed + suspend fun update( + params: OrganizationMemberUpdateParams = OrganizationMemberUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + suspend fun update( + requestOptions: RequestOptions + ): HttpResponseFor = + update(OrganizationMemberUpdateParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsyncImpl.kt index e63aa9bd..5159f637 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsyncImpl.kt @@ -4,51 +4,78 @@ package com.braintrustdata.api.services.async.organizations import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.OrganizationMemberUpdateParams import com.braintrustdata.api.models.PatchOrganizationMembersOutput -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class MemberServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : MemberServiceAsync { +class MemberServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + MemberServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: MemberServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): MemberServiceAsync.WithRawResponse = withRawResponse - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): MemberServiceAsync = + MemberServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** Modify organization membership */ override suspend fun update( params: OrganizationMemberUpdateParams, - requestOptions: RequestOptions - ): PatchOrganizationMembersOutput { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "organization", "members") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): PatchOrganizationMembersOutput = + // patch /v1/organization/members + withRawResponse().update(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + MemberServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): MemberServiceAsync.WithRawResponse = + MemberServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun update( + params: OrganizationMemberUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", "members") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsync.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsync.kt index 7e74a2fd..c129d008 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsync.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsync.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.async.projects +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchProjectLogsEventsResponse import com.braintrustdata.api.models.InsertEventsResponse @@ -12,36 +12,200 @@ import com.braintrustdata.api.models.ProjectLogFeedbackParams import com.braintrustdata.api.models.ProjectLogFetchParams import com.braintrustdata.api.models.ProjectLogFetchPostParams import com.braintrustdata.api.models.ProjectLogInsertParams +import com.google.errorprone.annotations.MustBeClosed interface LogServiceAsync { + /** + * 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: (ClientOptions.Builder) -> Unit): LogServiceAsync + /** Log feedback for a set of project logs events */ suspend fun feedback( + projectId: String, params: ProjectLogFeedbackParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): FeedbackResponseSchema = + feedback(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see feedback */ + suspend fun feedback( + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), ): FeedbackResponseSchema /** * Fetch the events in a project logs. Equivalent to the POST form of the same path, but with - * the parameters in the URL query rather than in the request body + * the parameters in the URL query rather than in the request body. For more complex queries, + * use the `POST /btql` endpoint. */ + suspend fun fetch( + projectId: String, + params: ProjectLogFetchParams = ProjectLogFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchProjectLogsEventsResponse = + fetch(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetch */ suspend fun fetch( params: ProjectLogFetchParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchProjectLogsEventsResponse + /** @see fetch */ + suspend fun fetch( + projectId: String, + requestOptions: RequestOptions, + ): FetchProjectLogsEventsResponse = + fetch(projectId, ProjectLogFetchParams.none(), requestOptions) + /** * Fetch the events in a project logs. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query + * parameters in the request body rather than in the URL query. For more complex queries, use + * the `POST /btql` endpoint. */ + suspend fun fetchPost( + projectId: String, + params: ProjectLogFetchPostParams = ProjectLogFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchProjectLogsEventsResponse = + fetchPost(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetchPost */ suspend fun fetchPost( params: ProjectLogFetchPostParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchProjectLogsEventsResponse + /** @see fetchPost */ + suspend fun fetchPost( + projectId: String, + requestOptions: RequestOptions, + ): FetchProjectLogsEventsResponse = + fetchPost(projectId, ProjectLogFetchPostParams.none(), requestOptions) + /** Insert a set of events into the project logs */ + suspend fun insert( + projectId: String, + params: ProjectLogInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): InsertEventsResponse = + insert(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see insert */ suspend fun insert( params: ProjectLogInsertParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): InsertEventsResponse + + /** A view of [LogServiceAsync] 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: (ClientOptions.Builder) -> Unit): LogServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project_logs/{project_id}/feedback`, but is + * otherwise the same as [LogServiceAsync.feedback]. + */ + @MustBeClosed + suspend fun feedback( + projectId: String, + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + feedback(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see feedback */ + @MustBeClosed + suspend fun feedback( + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project_logs/{project_id}/fetch`, but is + * otherwise the same as [LogServiceAsync.fetch]. + */ + @MustBeClosed + suspend fun fetch( + projectId: String, + params: ProjectLogFetchParams = ProjectLogFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetch(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetch */ + @MustBeClosed + suspend fun fetch( + params: ProjectLogFetchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetch */ + @MustBeClosed + suspend fun fetch( + projectId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetch(projectId, ProjectLogFetchParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/project_logs/{project_id}/fetch`, but is + * otherwise the same as [LogServiceAsync.fetchPost]. + */ + @MustBeClosed + suspend fun fetchPost( + projectId: String, + params: ProjectLogFetchPostParams = ProjectLogFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetchPost(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetchPost */ + @MustBeClosed + suspend fun fetchPost( + params: ProjectLogFetchPostParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetchPost */ + @MustBeClosed + suspend fun fetchPost( + projectId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetchPost(projectId, ProjectLogFetchPostParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/project_logs/{project_id}/insert`, but is + * otherwise the same as [LogServiceAsync.insert]. + */ + @MustBeClosed + suspend fun insert( + projectId: String, + params: ProjectLogInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + insert(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see insert */ + @MustBeClosed + suspend fun insert( + params: ProjectLogInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsyncImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsyncImpl.kt index 3ac16136..480f7252 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsyncImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsyncImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.async.projects import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepareAsync import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchProjectLogsEventsResponse import com.braintrustdata.api.models.InsertEventsResponse @@ -15,138 +23,181 @@ import com.braintrustdata.api.models.ProjectLogFeedbackParams import com.braintrustdata.api.models.ProjectLogFetchParams import com.braintrustdata.api.models.ProjectLogFetchPostParams import com.braintrustdata.api.models.ProjectLogInsertParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class LogServiceAsyncImpl -constructor( - private val clientOptions: ClientOptions, -) : LogServiceAsync { +class LogServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + LogServiceAsync { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: LogServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): LogServiceAsync.WithRawResponse = withRawResponse - private val feedbackHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): LogServiceAsync = + LogServiceAsyncImpl(clientOptions.toBuilder().apply(modifier).build()) - /** Log feedback for a set of project logs events */ override suspend fun feedback( params: ProjectLogFeedbackParams, - requestOptions: RequestOptions - ): FeedbackResponseSchema { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "feedback") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { feedbackHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): FeedbackResponseSchema = + // post /v1/project_logs/{project_id}/feedback + withRawResponse().feedback(params, requestOptions).parse() + + override suspend fun fetch( + params: ProjectLogFetchParams, + requestOptions: RequestOptions, + ): FetchProjectLogsEventsResponse = + // get /v1/project_logs/{project_id}/fetch + withRawResponse().fetch(params, requestOptions).parse() + + override suspend fun fetchPost( + params: ProjectLogFetchPostParams, + requestOptions: RequestOptions, + ): FetchProjectLogsEventsResponse = + // post /v1/project_logs/{project_id}/fetch + withRawResponse().fetchPost(params, requestOptions).parse() + + override suspend fun insert( + params: ProjectLogInsertParams, + requestOptions: RequestOptions, + ): InsertEventsResponse = + // post /v1/project_logs/{project_id}/insert + withRawResponse().insert(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + LogServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): LogServiceAsync.WithRawResponse = + LogServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val feedbackHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override suspend fun feedback( + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "feedback") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { feedbackHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a project logs. Equivalent to the POST form of the same path, but with - * the parameters in the URL query rather than in the request body - */ - override suspend fun fetch( - params: ProjectLogFetchParams, - requestOptions: RequestOptions - ): FetchProjectLogsEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { fetchHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun fetch( + params: ProjectLogFetchParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "fetch") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { fetchHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchPostHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchPostHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a project logs. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query - */ - override suspend fun fetchPost( - params: ProjectLogFetchPostParams, - requestOptions: RequestOptions - ): FetchProjectLogsEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { fetchPostHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun fetchPost( + params: ProjectLogFetchPostParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "fetch") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { fetchPostHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val insertHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val insertHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Insert a set of events into the project logs */ - override suspend fun insert( - params: ProjectLogInsertParams, - requestOptions: RequestOptions - ): InsertEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "insert") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> - response - .use { insertHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override suspend fun insert( + params: ProjectLogInsertParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "insert") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.executeAsync(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { insertHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclService.kt index 1d39e507..48cc29da 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Acl import com.braintrustdata.api.models.AclBatchUpdateParams import com.braintrustdata.api.models.AclBatchUpdateResponse @@ -14,9 +14,22 @@ import com.braintrustdata.api.models.AclFindAndDeleteParams import com.braintrustdata.api.models.AclListPage import com.braintrustdata.api.models.AclListParams import com.braintrustdata.api.models.AclRetrieveParams +import com.google.errorprone.annotations.MustBeClosed interface AclService { + /** + * 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: (ClientOptions.Builder) -> Unit): AclService + /** * Create a new acl. If there is an existing acl with the same contents as the one specified in * the request, will return the existing acl unmodified @@ -24,35 +37,163 @@ interface AclService { fun create(params: AclCreateParams, requestOptions: RequestOptions = RequestOptions.none()): Acl /** Get an acl object by its id */ + fun retrieve( + aclId: String, + params: AclRetrieveParams = AclRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Acl = retrieve(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: AclRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Acl + /** @see retrieve */ + fun retrieve(aclId: String, requestOptions: RequestOptions): Acl = + retrieve(aclId, AclRetrieveParams.none(), requestOptions) + /** * List out all acls. The acls are sorted by creation date, with the most recently-created acls * coming first */ fun list( params: AclListParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AclListPage /** Delete an acl object by its id */ + fun delete( + aclId: String, + params: AclDeleteParams = AclDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Acl = delete(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see delete */ fun delete(params: AclDeleteParams, requestOptions: RequestOptions = RequestOptions.none()): Acl + /** @see delete */ + fun delete(aclId: String, requestOptions: RequestOptions): Acl = + delete(aclId, AclDeleteParams.none(), requestOptions) + /** * Batch update acls. This operation is idempotent, so adding acls which already exist will have * no effect, and removing acls which do not exist will have no effect. */ fun batchUpdate( - params: AclBatchUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + params: AclBatchUpdateParams = AclBatchUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): AclBatchUpdateResponse + /** @see batchUpdate */ + fun batchUpdate(requestOptions: RequestOptions): AclBatchUpdateResponse = + batchUpdate(AclBatchUpdateParams.none(), requestOptions) + /** Delete a single acl */ fun findAndDelete( params: AclFindAndDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Acl + + /** A view of [AclService] 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: (ClientOptions.Builder) -> Unit): AclService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/acl`, but is otherwise the same as + * [AclService.create]. + */ + @MustBeClosed + fun create( + params: AclCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/acl/{acl_id}`, but is otherwise the same as + * [AclService.retrieve]. + */ + @MustBeClosed + fun retrieve( + aclId: String, + params: AclRetrieveParams = AclRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = retrieve(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: AclRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(aclId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(aclId, AclRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/acl`, but is otherwise the same as + * [AclService.list]. + */ + @MustBeClosed + fun list( + params: AclListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `delete /v1/acl/{acl_id}`, but is otherwise the same as + * [AclService.delete]. + */ + @MustBeClosed + fun delete( + aclId: String, + params: AclDeleteParams = AclDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = delete(params.toBuilder().aclId(aclId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: AclDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(aclId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(aclId, AclDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/acl/batch_update`, but is otherwise the same as + * [AclService.batchUpdate]. + */ + @MustBeClosed + fun batchUpdate( + params: AclBatchUpdateParams = AclBatchUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see batchUpdate */ + @MustBeClosed + fun batchUpdate(requestOptions: RequestOptions): HttpResponseFor = + batchUpdate(AclBatchUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/acl`, but is otherwise the same as + * [AclService.findAndDelete]. + */ + @MustBeClosed + fun findAndDelete( + params: AclFindAndDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclServiceImpl.kt index c9159b0c..4df68c46 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AclServiceImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Acl import com.braintrustdata.api.models.AclBatchUpdateParams import com.braintrustdata.api.models.AclBatchUpdateResponse @@ -15,187 +23,235 @@ import com.braintrustdata.api.models.AclCreateParams import com.braintrustdata.api.models.AclDeleteParams import com.braintrustdata.api.models.AclFindAndDeleteParams import com.braintrustdata.api.models.AclListPage +import com.braintrustdata.api.models.AclListPageResponse import com.braintrustdata.api.models.AclListParams import com.braintrustdata.api.models.AclRetrieveParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class AclServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : AclService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new acl. If there is an existing acl with the same contents as the one specified in - * the request, will return the existing acl unmodified - */ - override fun create(params: AclCreateParams, requestOptions: RequestOptions): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "acl") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + +class AclServiceImpl internal constructor(private val clientOptions: ClientOptions) : AclService { + + private val withRawResponse: AclService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): AclService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): AclService = + AclServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: AclCreateParams, requestOptions: RequestOptions): Acl = + // post /v1/acl + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: AclRetrieveParams, requestOptions: RequestOptions): Acl = + // get /v1/acl/{acl_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun list(params: AclListParams, requestOptions: RequestOptions): AclListPage = + // get /v1/acl + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: AclDeleteParams, requestOptions: RequestOptions): Acl = + // delete /v1/acl/{acl_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun batchUpdate( + params: AclBatchUpdateParams, + requestOptions: RequestOptions, + ): AclBatchUpdateResponse = + // post /v1/acl/batch_update + withRawResponse().batchUpdate(params, requestOptions).parse() + + override fun findAndDelete( + params: AclFindAndDeleteParams, + requestOptions: RequestOptions, + ): Acl = + // delete /v1/acl + withRawResponse().findAndDelete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AclService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): AclService.WithRawResponse = + AclServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: AclCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get an acl object by its id */ - override fun retrieve(params: AclRetrieveParams, requestOptions: RequestOptions): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "acl", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: AclRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aclId", params.aclId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * List out all acls. The acls are sorted by creation date, with the most recently-created acls - * coming first - */ - override fun list(params: AclListParams, requestOptions: RequestOptions): AclListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "acl") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: AclListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + AclListPage.builder() + .service(AclServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { AclListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete an acl object by its id */ - override fun delete(params: AclDeleteParams, requestOptions: RequestOptions): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "acl", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: AclDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aclId", params.aclId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val batchUpdateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val batchUpdateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Batch update acls. This operation is idempotent, so adding acls which already exist will have - * no effect, and removing acls which do not exist will have no effect. - */ - override fun batchUpdate( - params: AclBatchUpdateParams, - requestOptions: RequestOptions - ): AclBatchUpdateResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "acl", "batch-update") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { batchUpdateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun batchUpdate( + params: AclBatchUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl", "batch_update") + .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 { batchUpdateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val findAndDeleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val findAndDeleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) - /** Delete a single acl */ - override fun findAndDelete( - params: AclFindAndDeleteParams, - requestOptions: RequestOptions - ): Acl { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "acl") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { findAndDeleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun findAndDelete( + params: AclFindAndDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "acl") + .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 { findAndDeleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretService.kt index cb8dcfa9..a7ce70aa 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.AISecret import com.braintrustdata.api.models.AiSecretCreateParams import com.braintrustdata.api.models.AiSecretDeleteParams @@ -14,53 +14,103 @@ import com.braintrustdata.api.models.AiSecretListParams import com.braintrustdata.api.models.AiSecretReplaceParams import com.braintrustdata.api.models.AiSecretRetrieveParams import com.braintrustdata.api.models.AiSecretUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface AiSecretService { + /** + * 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: (ClientOptions.Builder) -> Unit): AiSecretService + /** * Create a new ai_secret. If there is an existing ai_secret with the same name as the one * specified in the request, will return the existing ai_secret unmodified */ fun create( params: AiSecretCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret /** Get an ai_secret object by its id */ + fun retrieve( + aiSecretId: String, + params: AiSecretRetrieveParams = AiSecretRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AISecret = retrieve(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: AiSecretRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + /** @see retrieve */ + fun retrieve(aiSecretId: String, requestOptions: RequestOptions): AISecret = + retrieve(aiSecretId, AiSecretRetrieveParams.none(), requestOptions) + /** * Partially update an ai_secret object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + aiSecretId: String, + params: AiSecretUpdateParams = AiSecretUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AISecret = update(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see update */ fun update( params: AiSecretUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + /** @see update */ + fun update(aiSecretId: String, requestOptions: RequestOptions): AISecret = + update(aiSecretId, AiSecretUpdateParams.none(), requestOptions) + /** * List out all ai_secrets. The ai_secrets are sorted by creation date, with the most * recently-created ai_secrets coming first */ fun list( - params: AiSecretListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: AiSecretListParams = AiSecretListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): AiSecretListPage + /** @see list */ + fun list(requestOptions: RequestOptions): AiSecretListPage = + list(AiSecretListParams.none(), requestOptions) + /** Delete an ai_secret object by its id */ + fun delete( + aiSecretId: String, + params: AiSecretDeleteParams = AiSecretDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AISecret = delete(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see delete */ fun delete( params: AiSecretDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + /** @see delete */ + fun delete(aiSecretId: String, requestOptions: RequestOptions): AISecret = + delete(aiSecretId, AiSecretDeleteParams.none(), requestOptions) + /** Delete a single ai_secret */ fun findAndDelete( params: AiSecretFindAndDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret /** @@ -69,6 +119,137 @@ interface AiSecretService { */ fun replace( params: AiSecretReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): AISecret + + /** A view of [AiSecretService] 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: (ClientOptions.Builder) -> Unit): AiSecretService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/ai_secret`, but is otherwise the same as + * [AiSecretService.create]. + */ + @MustBeClosed + fun create( + params: AiSecretCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/ai_secret/{ai_secret_id}`, but is otherwise the + * same as [AiSecretService.retrieve]. + */ + @MustBeClosed + fun retrieve( + aiSecretId: String, + params: AiSecretRetrieveParams = AiSecretRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: AiSecretRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + aiSecretId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(aiSecretId, AiSecretRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/ai_secret/{ai_secret_id}`, but is otherwise + * the same as [AiSecretService.update]. + */ + @MustBeClosed + fun update( + aiSecretId: String, + params: AiSecretUpdateParams = AiSecretUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: AiSecretUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update(aiSecretId: String, requestOptions: RequestOptions): HttpResponseFor = + update(aiSecretId, AiSecretUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/ai_secret`, but is otherwise the same as + * [AiSecretService.list]. + */ + @MustBeClosed + fun list( + params: AiSecretListParams = AiSecretListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(AiSecretListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/ai_secret/{ai_secret_id}`, but is otherwise + * the same as [AiSecretService.delete]. + */ + @MustBeClosed + fun delete( + aiSecretId: String, + params: AiSecretDeleteParams = AiSecretDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().aiSecretId(aiSecretId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: AiSecretDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(aiSecretId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(aiSecretId, AiSecretDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/ai_secret`, but is otherwise the same as + * [AiSecretService.findAndDelete]. + */ + @MustBeClosed + fun findAndDelete( + params: AiSecretFindAndDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `put /v1/ai_secret`, but is otherwise the same as + * [AiSecretService.replace]. + */ + @MustBeClosed + fun replace( + params: AiSecretReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceImpl.kt index 4b6cd903..21c3bba8 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceImpl.kt @@ -4,232 +4,299 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.AISecret import com.braintrustdata.api.models.AiSecretCreateParams import com.braintrustdata.api.models.AiSecretDeleteParams import com.braintrustdata.api.models.AiSecretFindAndDeleteParams import com.braintrustdata.api.models.AiSecretListPage +import com.braintrustdata.api.models.AiSecretListPageResponse import com.braintrustdata.api.models.AiSecretListParams import com.braintrustdata.api.models.AiSecretReplaceParams import com.braintrustdata.api.models.AiSecretRetrieveParams import com.braintrustdata.api.models.AiSecretUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class AiSecretServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : AiSecretService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new ai_secret. If there is an existing ai_secret with the same name as the one - * specified in the request, will return the existing ai_secret unmodified - */ - override fun create(params: AiSecretCreateParams, requestOptions: RequestOptions): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } + +class AiSecretServiceImpl internal constructor(private val clientOptions: ClientOptions) : + AiSecretService { + + private val withRawResponse: AiSecretService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withRawResponse(): AiSecretService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): AiSecretService = + AiSecretServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: AiSecretCreateParams, requestOptions: RequestOptions): AISecret = + // post /v1/ai_secret + withRawResponse().create(params, requestOptions).parse() - /** Get an ai_secret object by its id */ override fun retrieve( params: AiSecretRetrieveParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "ai_secret", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): AISecret = + // get /v1/ai_secret/{ai_secret_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: AiSecretUpdateParams, requestOptions: RequestOptions): AISecret = + // patch /v1/ai_secret/{ai_secret_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: AiSecretListParams, + requestOptions: RequestOptions, + ): AiSecretListPage = + // get /v1/ai_secret + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: AiSecretDeleteParams, requestOptions: RequestOptions): AISecret = + // delete /v1/ai_secret/{ai_secret_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun findAndDelete( + params: AiSecretFindAndDeleteParams, + requestOptions: RequestOptions, + ): AISecret = + // delete /v1/ai_secret + withRawResponse().findAndDelete(params, requestOptions).parse() + + override fun replace(params: AiSecretReplaceParams, requestOptions: RequestOptions): AISecret = + // put /v1/ai_secret + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AiSecretService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): AiSecretService.WithRawResponse = + AiSecretServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: AiSecretCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update an ai_secret object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update(params: AiSecretUpdateParams, requestOptions: RequestOptions): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "ai_secret", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: AiSecretRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aiSecretId", params.aiSecretId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all ai_secrets. The ai_secrets are sorted by creation date, with the most - * recently-created ai_secrets coming first - */ - override fun list( - params: AiSecretListParams, - requestOptions: RequestOptions - ): AiSecretListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun update( + params: AiSecretUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aiSecretId", params.aiSecretId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { AiSecretListPage.of(this, params, it) } + } + } + + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: AiSecretListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + AiSecretListPage.builder() + .service(AiSecretServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete an ai_secret object by its id */ - override fun delete(params: AiSecretDeleteParams, requestOptions: RequestOptions): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "ai_secret", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: AiSecretDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("aiSecretId", params.aiSecretId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val findAndDeleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val findAndDeleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete a single ai_secret */ - override fun findAndDelete( - params: AiSecretFindAndDeleteParams, - requestOptions: RequestOptions - ): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { findAndDeleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun findAndDelete( + params: AiSecretFindAndDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .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 { findAndDeleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace ai_secret. If there is an existing ai_secret with the same name as the one - * specified in the request, will replace the existing ai_secret with the provided fields - */ - override fun replace(params: AiSecretReplaceParams, requestOptions: RequestOptions): AISecret { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "ai_secret") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: AiSecretReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "ai_secret") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyService.kt index 1dde7295..44bde19d 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.ApiKey import com.braintrustdata.api.models.ApiKeyCreateParams import com.braintrustdata.api.models.ApiKeyDeleteParams @@ -12,36 +12,159 @@ import com.braintrustdata.api.models.ApiKeyListPage import com.braintrustdata.api.models.ApiKeyListParams import com.braintrustdata.api.models.ApiKeyRetrieveParams import com.braintrustdata.api.models.CreateApiKeyOutput +import com.google.errorprone.annotations.MustBeClosed interface ApiKeyService { + /** + * 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: (ClientOptions.Builder) -> Unit): ApiKeyService + /** * Create a new api_key. It is possible to have multiple API keys with the same name. There is * no de-duplication */ fun create( params: ApiKeyCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): CreateApiKeyOutput /** Get an api_key object by its id */ + fun retrieve( + apiKeyId: String, + params: ApiKeyRetrieveParams = ApiKeyRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ApiKey = retrieve(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: ApiKeyRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ApiKey + /** @see retrieve */ + fun retrieve(apiKeyId: String, requestOptions: RequestOptions): ApiKey = + retrieve(apiKeyId, ApiKeyRetrieveParams.none(), requestOptions) + /** * List out all api_keys. The api_keys are sorted by creation date, with the most * recently-created api_keys coming first */ fun list( - params: ApiKeyListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ApiKeyListParams = ApiKeyListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ApiKeyListPage + /** @see list */ + fun list(requestOptions: RequestOptions): ApiKeyListPage = + list(ApiKeyListParams.none(), requestOptions) + /** Delete an api_key object by its id */ + fun delete( + apiKeyId: String, + params: ApiKeyDeleteParams = ApiKeyDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ApiKey = delete(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see delete */ fun delete( params: ApiKeyDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ApiKey + + /** @see delete */ + fun delete(apiKeyId: String, requestOptions: RequestOptions): ApiKey = + delete(apiKeyId, ApiKeyDeleteParams.none(), requestOptions) + + /** A view of [ApiKeyService] 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: (ClientOptions.Builder) -> Unit): ApiKeyService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/api_key`, but is otherwise the same as + * [ApiKeyService.create]. + */ + @MustBeClosed + fun create( + params: ApiKeyCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/api_key/{api_key_id}`, but is otherwise the same + * as [ApiKeyService.retrieve]. + */ + @MustBeClosed + fun retrieve( + apiKeyId: String, + params: ApiKeyRetrieveParams = ApiKeyRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: ApiKeyRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(apiKeyId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(apiKeyId, ApiKeyRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/api_key`, but is otherwise the same as + * [ApiKeyService.list]. + */ + @MustBeClosed + fun list( + params: ApiKeyListParams = ApiKeyListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ApiKeyListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/api_key/{api_key_id}`, but is otherwise the + * same as [ApiKeyService.delete]. + */ + @MustBeClosed + fun delete( + apiKeyId: String, + params: ApiKeyDeleteParams = ApiKeyDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().apiKeyId(apiKeyId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: ApiKeyDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(apiKeyId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(apiKeyId, ApiKeyDeleteParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceImpl.kt index 199c4382..b1d18588 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceImpl.kt @@ -4,139 +4,188 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.ApiKey import com.braintrustdata.api.models.ApiKeyCreateParams import com.braintrustdata.api.models.ApiKeyDeleteParams import com.braintrustdata.api.models.ApiKeyListPage +import com.braintrustdata.api.models.ApiKeyListPageResponse import com.braintrustdata.api.models.ApiKeyListParams import com.braintrustdata.api.models.ApiKeyRetrieveParams import com.braintrustdata.api.models.CreateApiKeyOutput -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ApiKeyServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : ApiKeyService { +class ApiKeyServiceImpl internal constructor(private val clientOptions: ClientOptions) : + ApiKeyService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ApiKeyService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ApiKeyService.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ApiKeyService = + ApiKeyServiceImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new api_key. It is possible to have multiple API keys with the same name. There is - * no de-duplication - */ override fun create( params: ApiKeyCreateParams, - requestOptions: RequestOptions - ): CreateApiKeyOutput { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "api_key") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): CreateApiKeyOutput = + // post /v1/api_key + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: ApiKeyRetrieveParams, requestOptions: RequestOptions): ApiKey = + // get /v1/api_key/{api_key_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun list(params: ApiKeyListParams, requestOptions: RequestOptions): ApiKeyListPage = + // get /v1/api_key + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: ApiKeyDeleteParams, requestOptions: RequestOptions): ApiKey = + // delete /v1/api_key/{api_key_id} + withRawResponse().delete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ApiKeyService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ApiKeyService.WithRawResponse = + ApiKeyServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ApiKeyCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get an api_key object by its id */ - override fun retrieve(params: ApiKeyRetrieveParams, requestOptions: RequestOptions): ApiKey { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "api_key", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: ApiKeyRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("apiKeyId", params.apiKeyId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - /** - * List out all api_keys. The api_keys are sorted by creation date, with the most - * recently-created api_keys coming first - */ - override fun list(params: ApiKeyListParams, requestOptions: RequestOptions): ApiKeyListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "api_key") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: ApiKeyListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + ApiKeyListPage.builder() + .service(ApiKeyServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { ApiKeyListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete an api_key object by its id */ - override fun delete(params: ApiKeyDeleteParams, requestOptions: RequestOptions): ApiKey { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "api_key", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: ApiKeyDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("apiKeyId", params.apiKeyId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "api_key", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetService.kt index 5caf0e79..8e828a0d 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Dataset import com.braintrustdata.api.models.DatasetCreateParams import com.braintrustdata.api.models.DatasetDeleteParams @@ -21,82 +21,413 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchDatasetEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeDatasetResponse +import com.google.errorprone.annotations.MustBeClosed interface DatasetService { + /** + * 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: (ClientOptions.Builder) -> Unit): DatasetService + /** * Create a new dataset. If there is an existing dataset in the project with the same name as * the one specified in the request, will return the existing dataset unmodified */ fun create( params: DatasetCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset /** Get a dataset object by its id */ + fun retrieve( + datasetId: String, + params: DatasetRetrieveParams = DatasetRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Dataset = retrieve(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: DatasetRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset + /** @see retrieve */ + fun retrieve(datasetId: String, requestOptions: RequestOptions): Dataset = + retrieve(datasetId, DatasetRetrieveParams.none(), requestOptions) + /** * Partially update a dataset object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + datasetId: String, + params: DatasetUpdateParams = DatasetUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Dataset = update(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see update */ fun update( params: DatasetUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset + /** @see update */ + fun update(datasetId: String, requestOptions: RequestOptions): Dataset = + update(datasetId, DatasetUpdateParams.none(), requestOptions) + /** * List out all datasets. The datasets are sorted by creation date, with the most * recently-created datasets coming first */ fun list( - params: DatasetListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: DatasetListParams = DatasetListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): DatasetListPage + /** @see list */ + fun list(requestOptions: RequestOptions): DatasetListPage = + list(DatasetListParams.none(), requestOptions) + /** Delete a dataset object by its id */ + fun delete( + datasetId: String, + params: DatasetDeleteParams = DatasetDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Dataset = delete(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see delete */ fun delete( params: DatasetDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Dataset + /** @see delete */ + fun delete(datasetId: String, requestOptions: RequestOptions): Dataset = + delete(datasetId, DatasetDeleteParams.none(), requestOptions) + /** Log feedback for a set of dataset events */ + fun feedback( + datasetId: String, + params: DatasetFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FeedbackResponseSchema = + feedback(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see feedback */ fun feedback( params: DatasetFeedbackParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FeedbackResponseSchema /** * Fetch the events in a dataset. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body + * parameters in the URL query rather than in the request body. For more complex queries, use + * the `POST /btql` endpoint. */ + fun fetch( + datasetId: String, + params: DatasetFetchParams = DatasetFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchDatasetEventsResponse = + fetch(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetch */ fun fetch( params: DatasetFetchParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchDatasetEventsResponse + /** @see fetch */ + fun fetch(datasetId: String, requestOptions: RequestOptions): FetchDatasetEventsResponse = + fetch(datasetId, DatasetFetchParams.none(), requestOptions) + /** * Fetch the events in a dataset. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query + * parameters in the request body rather than in the URL query. For more complex queries, use + * the `POST /btql` endpoint. */ + fun fetchPost( + datasetId: String, + params: DatasetFetchPostParams = DatasetFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchDatasetEventsResponse = + fetchPost(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetchPost */ fun fetchPost( params: DatasetFetchPostParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchDatasetEventsResponse + /** @see fetchPost */ + fun fetchPost(datasetId: String, requestOptions: RequestOptions): FetchDatasetEventsResponse = + fetchPost(datasetId, DatasetFetchPostParams.none(), requestOptions) + /** Insert a set of events into the dataset */ fun insert( + datasetId: String, params: DatasetInsertParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): InsertEventsResponse = + insert(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see insert */ + fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), ): InsertEventsResponse /** Summarize dataset */ + fun summarize( + datasetId: String, + params: DatasetSummarizeParams = DatasetSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SummarizeDatasetResponse = + summarize(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see summarize */ fun summarize( params: DatasetSummarizeParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): SummarizeDatasetResponse + + /** @see summarize */ + fun summarize(datasetId: String, requestOptions: RequestOptions): SummarizeDatasetResponse = + summarize(datasetId, DatasetSummarizeParams.none(), requestOptions) + + /** A view of [DatasetService] 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: (ClientOptions.Builder) -> Unit): DatasetService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/dataset`, but is otherwise the same as + * [DatasetService.create]. + */ + @MustBeClosed + fun create( + params: DatasetCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/dataset/{dataset_id}`, but is otherwise the same + * as [DatasetService.retrieve]. + */ + @MustBeClosed + fun retrieve( + datasetId: String, + params: DatasetRetrieveParams = DatasetRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: DatasetRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(datasetId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(datasetId, DatasetRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/dataset/{dataset_id}`, but is otherwise the + * same as [DatasetService.update]. + */ + @MustBeClosed + fun update( + datasetId: String, + params: DatasetUpdateParams = DatasetUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: DatasetUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update(datasetId: String, requestOptions: RequestOptions): HttpResponseFor = + update(datasetId, DatasetUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/dataset`, but is otherwise the same as + * [DatasetService.list]. + */ + @MustBeClosed + fun list( + params: DatasetListParams = DatasetListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(DatasetListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/dataset/{dataset_id}`, but is otherwise the + * same as [DatasetService.delete]. + */ + @MustBeClosed + fun delete( + datasetId: String, + params: DatasetDeleteParams = DatasetDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: DatasetDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(datasetId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(datasetId, DatasetDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/dataset/{dataset_id}/feedback`, but is + * otherwise the same as [DatasetService.feedback]. + */ + @MustBeClosed + fun feedback( + datasetId: String, + params: DatasetFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + feedback(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see feedback */ + @MustBeClosed + fun feedback( + params: DatasetFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/dataset/{dataset_id}/fetch`, but is otherwise + * the same as [DatasetService.fetch]. + */ + @MustBeClosed + fun fetch( + datasetId: String, + params: DatasetFetchParams = DatasetFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetch(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetch */ + @MustBeClosed + fun fetch( + params: DatasetFetchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetch */ + @MustBeClosed + fun fetch( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetch(datasetId, DatasetFetchParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/dataset/{dataset_id}/fetch`, but is otherwise + * the same as [DatasetService.fetchPost]. + */ + @MustBeClosed + fun fetchPost( + datasetId: String, + params: DatasetFetchPostParams = DatasetFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetchPost(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see fetchPost */ + @MustBeClosed + fun fetchPost( + params: DatasetFetchPostParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetchPost */ + @MustBeClosed + fun fetchPost( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetchPost(datasetId, DatasetFetchPostParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/dataset/{dataset_id}/insert`, but is otherwise + * the same as [DatasetService.insert]. + */ + @MustBeClosed + fun insert( + datasetId: String, + params: DatasetInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + insert(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see insert */ + @MustBeClosed + fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/dataset/{dataset_id}/summarize`, but is + * otherwise the same as [DatasetService.summarize]. + */ + @MustBeClosed + fun summarize( + datasetId: String, + params: DatasetSummarizeParams = DatasetSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + summarize(params.toBuilder().datasetId(datasetId).build(), requestOptions) + + /** @see summarize */ + @MustBeClosed + fun summarize( + params: DatasetSummarizeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see summarize */ + @MustBeClosed + fun summarize( + datasetId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + summarize(datasetId, DatasetSummarizeParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceImpl.kt index 8213b074..3d7e19da 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Dataset import com.braintrustdata.api.models.DatasetCreateParams import com.braintrustdata.api.models.DatasetDeleteParams @@ -16,6 +24,7 @@ import com.braintrustdata.api.models.DatasetFetchParams import com.braintrustdata.api.models.DatasetFetchPostParams import com.braintrustdata.api.models.DatasetInsertParams import com.braintrustdata.api.models.DatasetListPage +import com.braintrustdata.api.models.DatasetListPageResponse import com.braintrustdata.api.models.DatasetListParams import com.braintrustdata.api.models.DatasetRetrieveParams import com.braintrustdata.api.models.DatasetSummarizeParams @@ -24,307 +33,389 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchDatasetEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeDatasetResponse -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class DatasetServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : DatasetService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new dataset. If there is an existing dataset in the project with the same name as - * the one specified in the request, will return the existing dataset unmodified - */ - override fun create(params: DatasetCreateParams, requestOptions: RequestOptions): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + +class DatasetServiceImpl internal constructor(private val clientOptions: ClientOptions) : + DatasetService { + + private val withRawResponse: DatasetService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): DatasetService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): DatasetService = + DatasetServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: DatasetCreateParams, requestOptions: RequestOptions): Dataset = + // post /v1/dataset + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: DatasetRetrieveParams, requestOptions: RequestOptions): Dataset = + // get /v1/dataset/{dataset_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: DatasetUpdateParams, requestOptions: RequestOptions): Dataset = + // patch /v1/dataset/{dataset_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list(params: DatasetListParams, requestOptions: RequestOptions): DatasetListPage = + // get /v1/dataset + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: DatasetDeleteParams, requestOptions: RequestOptions): Dataset = + // delete /v1/dataset/{dataset_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun feedback( + params: DatasetFeedbackParams, + requestOptions: RequestOptions, + ): FeedbackResponseSchema = + // post /v1/dataset/{dataset_id}/feedback + withRawResponse().feedback(params, requestOptions).parse() + + override fun fetch( + params: DatasetFetchParams, + requestOptions: RequestOptions, + ): FetchDatasetEventsResponse = + // get /v1/dataset/{dataset_id}/fetch + withRawResponse().fetch(params, requestOptions).parse() + + override fun fetchPost( + params: DatasetFetchPostParams, + requestOptions: RequestOptions, + ): FetchDatasetEventsResponse = + // post /v1/dataset/{dataset_id}/fetch + withRawResponse().fetchPost(params, requestOptions).parse() + + override fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions, + ): InsertEventsResponse = + // post /v1/dataset/{dataset_id}/insert + withRawResponse().insert(params, requestOptions).parse() + + override fun summarize( + params: DatasetSummarizeParams, + requestOptions: RequestOptions, + ): SummarizeDatasetResponse = + // get /v1/dataset/{dataset_id}/summarize + withRawResponse().summarize(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + DatasetService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): DatasetService.WithRawResponse = + DatasetServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: DatasetCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get a dataset object by its id */ - override fun retrieve(params: DatasetRetrieveParams, requestOptions: RequestOptions): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: DatasetRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a dataset object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update(params: DatasetUpdateParams, requestOptions: RequestOptions): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "dataset", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: DatasetUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - /** - * List out all datasets. The datasets are sorted by creation date, with the most - * recently-created datasets coming first - */ - override fun list(params: DatasetListParams, requestOptions: RequestOptions): DatasetListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: DatasetListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { DatasetListPage.of(this, params, it) } + .let { + DatasetListPage.builder() + .service(DatasetServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a dataset object by its id */ - override fun delete(params: DatasetDeleteParams, requestOptions: RequestOptions): Dataset { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "dataset", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: DatasetDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val feedbackHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val feedbackHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Log feedback for a set of dataset events */ - override fun feedback( - params: DatasetFeedbackParams, - requestOptions: RequestOptions - ): FeedbackResponseSchema { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset", params.getPathParam(0), "feedback") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { feedbackHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun feedback( + params: DatasetFeedbackParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "feedback") + .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 { feedbackHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a dataset. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body - */ - override fun fetch( - params: DatasetFetchParams, - requestOptions: RequestOptions - ): FetchDatasetEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { fetchHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun fetch( + params: DatasetFetchParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "fetch") + .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 { fetchHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchPostHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchPostHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a dataset. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query - */ - override fun fetchPost( - params: DatasetFetchPostParams, - requestOptions: RequestOptions - ): FetchDatasetEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { fetchPostHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun fetchPost( + params: DatasetFetchPostParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "fetch") + .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 { fetchPostHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val insertHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val insertHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Insert a set of events into the dataset */ - override fun insert( - params: DatasetInsertParams, - requestOptions: RequestOptions - ): InsertEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "dataset", params.getPathParam(0), "insert") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { insertHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun insert( + params: DatasetInsertParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "insert") + .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 { insertHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val summarizeHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val summarizeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Summarize dataset */ - override fun summarize( - params: DatasetSummarizeParams, - requestOptions: RequestOptions - ): SummarizeDatasetResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "dataset", params.getPathParam(0), "summarize") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { summarizeHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun summarize( + params: DatasetSummarizeParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("datasetId", params.datasetId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "dataset", params._pathParam(0), "summarize") + .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 { summarizeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarService.kt index 77061864..88dcfa9f 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.EnvVar import com.braintrustdata.api.models.EnvVarCreateParams import com.braintrustdata.api.models.EnvVarDeleteParams @@ -13,32 +13,63 @@ import com.braintrustdata.api.models.EnvVarListResponse import com.braintrustdata.api.models.EnvVarReplaceParams import com.braintrustdata.api.models.EnvVarRetrieveParams import com.braintrustdata.api.models.EnvVarUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface EnvVarService { + /** + * 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: (ClientOptions.Builder) -> Unit): EnvVarService + /** * Create a new env_var. If there is an existing env_var with the same name as the one specified * in the request, will return the existing env_var unmodified */ fun create( params: EnvVarCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar /** Get an env_var object by its id */ + fun retrieve( + envVarId: String, + params: EnvVarRetrieveParams = EnvVarRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): EnvVar = retrieve(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: EnvVarRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar + /** @see retrieve */ + fun retrieve(envVarId: String, requestOptions: RequestOptions): EnvVar = + retrieve(envVarId, EnvVarRetrieveParams.none(), requestOptions) + /** * Partially update an env_var object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + envVarId: String, + params: EnvVarUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): EnvVar = update(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see update */ fun update( params: EnvVarUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar /** @@ -46,22 +77,150 @@ interface EnvVarService { * recently-created env_vars coming first */ fun list( - params: EnvVarListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: EnvVarListParams = EnvVarListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVarListResponse + /** @see list */ + fun list(requestOptions: RequestOptions): EnvVarListResponse = + list(EnvVarListParams.none(), requestOptions) + /** Delete an env_var object by its id */ + fun delete( + envVarId: String, + params: EnvVarDeleteParams = EnvVarDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): EnvVar = delete(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see delete */ fun delete( params: EnvVarDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar + /** @see delete */ + fun delete(envVarId: String, requestOptions: RequestOptions): EnvVar = + delete(envVarId, EnvVarDeleteParams.none(), requestOptions) + /** * Create or replace env_var. If there is an existing env_var with the same name as the one * specified in the request, will replace the existing env_var with the provided fields */ fun replace( params: EnvVarReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): EnvVar + + /** A view of [EnvVarService] 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: (ClientOptions.Builder) -> Unit): EnvVarService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/env_var`, but is otherwise the same as + * [EnvVarService.create]. + */ + @MustBeClosed + fun create( + params: EnvVarCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/env_var/{env_var_id}`, but is otherwise the same + * as [EnvVarService.retrieve]. + */ + @MustBeClosed + fun retrieve( + envVarId: String, + params: EnvVarRetrieveParams = EnvVarRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: EnvVarRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(envVarId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(envVarId, EnvVarRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/env_var/{env_var_id}`, but is otherwise the + * same as [EnvVarService.update]. + */ + @MustBeClosed + fun update( + envVarId: String, + params: EnvVarUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: EnvVarUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/env_var`, but is otherwise the same as + * [EnvVarService.list]. + */ + @MustBeClosed + fun list( + params: EnvVarListParams = EnvVarListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(EnvVarListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/env_var/{env_var_id}`, but is otherwise the + * same as [EnvVarService.delete]. + */ + @MustBeClosed + fun delete( + envVarId: String, + params: EnvVarDeleteParams = EnvVarDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().envVarId(envVarId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: EnvVarDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(envVarId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(envVarId, EnvVarDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/env_var`, but is otherwise the same as + * [EnvVarService.replace]. + */ + @MustBeClosed + fun replace( + params: EnvVarReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceImpl.kt index 1807abb1..4b467d24 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.EnvVar import com.braintrustdata.api.models.EnvVarCreateParams import com.braintrustdata.api.models.EnvVarDeleteParams @@ -16,185 +24,225 @@ import com.braintrustdata.api.models.EnvVarListResponse import com.braintrustdata.api.models.EnvVarReplaceParams import com.braintrustdata.api.models.EnvVarRetrieveParams import com.braintrustdata.api.models.EnvVarUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class EnvVarServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : EnvVarService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new env_var. If there is an existing env_var with the same name as the one specified - * in the request, will return the existing env_var unmodified - */ - override fun create(params: EnvVarCreateParams, requestOptions: RequestOptions): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "env_var") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } + +class EnvVarServiceImpl internal constructor(private val clientOptions: ClientOptions) : + EnvVarService { + + private val withRawResponse: EnvVarService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get an env_var object by its id */ - override fun retrieve(params: EnvVarRetrieveParams, requestOptions: RequestOptions): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "env_var", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun withRawResponse(): EnvVarService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): EnvVarService = + EnvVarServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: EnvVarCreateParams, requestOptions: RequestOptions): EnvVar = + // post /v1/env_var + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: EnvVarRetrieveParams, requestOptions: RequestOptions): EnvVar = + // get /v1/env_var/{env_var_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: EnvVarUpdateParams, requestOptions: RequestOptions): EnvVar = + // patch /v1/env_var/{env_var_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: EnvVarListParams, + requestOptions: RequestOptions, + ): EnvVarListResponse = + // get /v1/env_var + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: EnvVarDeleteParams, requestOptions: RequestOptions): EnvVar = + // delete /v1/env_var/{env_var_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace(params: EnvVarReplaceParams, requestOptions: RequestOptions): EnvVar = + // put /v1/env_var + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + EnvVarService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): EnvVarService.WithRawResponse = + EnvVarServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: EnvVarCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update an env_var object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update(params: EnvVarUpdateParams, requestOptions: RequestOptions): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "env_var", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: EnvVarRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("envVarId", params.envVarId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: EnvVarUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("envVarId", params.envVarId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } - /** - * List out all env_vars. The env_vars are sorted by creation date, with the most - * recently-created env_vars coming first - */ - override fun list( - params: EnvVarListParams, - requestOptions: RequestOptions - ): EnvVarListResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "env_var") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: EnvVarListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete an env_var object by its id */ - override fun delete(params: EnvVarDeleteParams, requestOptions: RequestOptions): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "env_var", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: EnvVarDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("envVarId", params.envVarId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace env_var. If there is an existing env_var with the same name as the one - * specified in the request, will replace the existing env_var with the provided fields - */ - override fun replace(params: EnvVarReplaceParams, requestOptions: RequestOptions): EnvVar { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "env_var") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: EnvVarReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "env_var") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalService.kt index f9242a7c..1e691310 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalService.kt @@ -1,15 +1,28 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.EvalCreateParams import com.braintrustdata.api.models.SummarizeExperimentResponse +import com.google.errorprone.annotations.MustBeClosed interface EvalService { + /** + * 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: (ClientOptions.Builder) -> Unit): EvalService + /** * Launch an evaluation. This is the API-equivalent of the `Eval` function that is built into * the Braintrust SDK. In the Eval API, you provide pointers to a dataset, task function, and @@ -19,6 +32,27 @@ interface EvalService { */ fun create( params: EvalCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): SummarizeExperimentResponse + + /** A view of [EvalService] 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: (ClientOptions.Builder) -> Unit): EvalService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/eval`, but is otherwise the same as + * [EvalService.create]. + */ + @MustBeClosed + fun create( + params: EvalCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalServiceImpl.kt index 2811b4d7..d368b020 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/EvalServiceImpl.kt @@ -4,57 +4,75 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.EvalCreateParams import com.braintrustdata.api.models.SummarizeExperimentResponse -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class EvalServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : EvalService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - /** - * Launch an evaluation. This is the API-equivalent of the `Eval` function that is built into - * the Braintrust SDK. In the Eval API, you provide pointers to a dataset, task function, and - * scoring functions. The API will then run the evaluation, create an experiment, and return the - * results along with a link to the experiment. To learn more about evals, see the - * [Evals guide](https://www.braintrust.dev/docs/guides/evals). - */ + +class EvalServiceImpl internal constructor(private val clientOptions: ClientOptions) : EvalService { + + private val withRawResponse: EvalService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): EvalService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): EvalService = + EvalServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + override fun create( params: EvalCreateParams, - requestOptions: RequestOptions - ): SummarizeExperimentResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "eval") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): SummarizeExperimentResponse = + // post /v1/eval + withRawResponse().create(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + EvalService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): EvalService.WithRawResponse = + EvalServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: EvalCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "eval") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentService.kt index ad57304b..dc9f7709 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Experiment import com.braintrustdata.api.models.ExperimentCreateParams import com.braintrustdata.api.models.ExperimentDeleteParams @@ -21,82 +21,430 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchExperimentEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeExperimentResponse +import com.google.errorprone.annotations.MustBeClosed interface ExperimentService { + /** + * 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: (ClientOptions.Builder) -> Unit): ExperimentService + /** * Create a new experiment. If there is an existing experiment in the project with the same name * as the one specified in the request, will return the existing experiment unmodified */ fun create( params: ExperimentCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment /** Get an experiment object by its id */ + fun retrieve( + experimentId: String, + params: ExperimentRetrieveParams = ExperimentRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Experiment = retrieve(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: ExperimentRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment + /** @see retrieve */ + fun retrieve(experimentId: String, requestOptions: RequestOptions): Experiment = + retrieve(experimentId, ExperimentRetrieveParams.none(), requestOptions) + /** * Partially update an experiment object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + experimentId: String, + params: ExperimentUpdateParams = ExperimentUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Experiment = update(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see update */ fun update( params: ExperimentUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment + /** @see update */ + fun update(experimentId: String, requestOptions: RequestOptions): Experiment = + update(experimentId, ExperimentUpdateParams.none(), requestOptions) + /** * List out all experiments. The experiments are sorted by creation date, with the most * recently-created experiments coming first */ fun list( - params: ExperimentListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ExperimentListParams = ExperimentListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ExperimentListPage + /** @see list */ + fun list(requestOptions: RequestOptions): ExperimentListPage = + list(ExperimentListParams.none(), requestOptions) + /** Delete an experiment object by its id */ + fun delete( + experimentId: String, + params: ExperimentDeleteParams = ExperimentDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Experiment = delete(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see delete */ fun delete( params: ExperimentDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Experiment + /** @see delete */ + fun delete(experimentId: String, requestOptions: RequestOptions): Experiment = + delete(experimentId, ExperimentDeleteParams.none(), requestOptions) + /** Log feedback for a set of experiment events */ + fun feedback( + experimentId: String, + params: ExperimentFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FeedbackResponseSchema = + feedback(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see feedback */ fun feedback( params: ExperimentFeedbackParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FeedbackResponseSchema /** * Fetch the events in an experiment. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body + * parameters in the URL query rather than in the request body. For more complex queries, use + * the `POST /btql` endpoint. */ + fun fetch( + experimentId: String, + params: ExperimentFetchParams = ExperimentFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchExperimentEventsResponse = + fetch(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetch */ fun fetch( params: ExperimentFetchParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchExperimentEventsResponse + /** @see fetch */ + fun fetch(experimentId: String, requestOptions: RequestOptions): FetchExperimentEventsResponse = + fetch(experimentId, ExperimentFetchParams.none(), requestOptions) + /** * Fetch the events in an experiment. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query + * parameters in the request body rather than in the URL query. For more complex queries, use + * the `POST /btql` endpoint. */ + fun fetchPost( + experimentId: String, + params: ExperimentFetchPostParams = ExperimentFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchExperimentEventsResponse = + fetchPost(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetchPost */ fun fetchPost( params: ExperimentFetchPostParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchExperimentEventsResponse + /** @see fetchPost */ + fun fetchPost( + experimentId: String, + requestOptions: RequestOptions, + ): FetchExperimentEventsResponse = + fetchPost(experimentId, ExperimentFetchPostParams.none(), requestOptions) + /** Insert a set of events into the experiment */ fun insert( + experimentId: String, params: ExperimentInsertParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): InsertEventsResponse = + insert(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see insert */ + fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), ): InsertEventsResponse /** Summarize experiment */ + fun summarize( + experimentId: String, + params: ExperimentSummarizeParams = ExperimentSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SummarizeExperimentResponse = + summarize(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see summarize */ fun summarize( params: ExperimentSummarizeParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): SummarizeExperimentResponse + + /** @see summarize */ + fun summarize( + experimentId: String, + requestOptions: RequestOptions, + ): SummarizeExperimentResponse = + summarize(experimentId, ExperimentSummarizeParams.none(), requestOptions) + + /** A view of [ExperimentService] 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: (ClientOptions.Builder) -> Unit + ): ExperimentService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/experiment`, but is otherwise the same as + * [ExperimentService.create]. + */ + @MustBeClosed + fun create( + params: ExperimentCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/experiment/{experiment_id}`, but is otherwise + * the same as [ExperimentService.retrieve]. + */ + @MustBeClosed + fun retrieve( + experimentId: String, + params: ExperimentRetrieveParams = ExperimentRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: ExperimentRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(experimentId, ExperimentRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/experiment/{experiment_id}`, but is otherwise + * the same as [ExperimentService.update]. + */ + @MustBeClosed + fun update( + experimentId: String, + params: ExperimentUpdateParams = ExperimentUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: ExperimentUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(experimentId, ExperimentUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/experiment`, but is otherwise the same as + * [ExperimentService.list]. + */ + @MustBeClosed + fun list( + params: ExperimentListParams = ExperimentListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ExperimentListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/experiment/{experiment_id}`, but is otherwise + * the same as [ExperimentService.delete]. + */ + @MustBeClosed + fun delete( + experimentId: String, + params: ExperimentDeleteParams = ExperimentDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: ExperimentDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(experimentId, ExperimentDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/experiment/{experiment_id}/feedback`, but is + * otherwise the same as [ExperimentService.feedback]. + */ + @MustBeClosed + fun feedback( + experimentId: String, + params: ExperimentFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + feedback(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see feedback */ + @MustBeClosed + fun feedback( + params: ExperimentFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/experiment/{experiment_id}/fetch`, but is + * otherwise the same as [ExperimentService.fetch]. + */ + @MustBeClosed + fun fetch( + experimentId: String, + params: ExperimentFetchParams = ExperimentFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetch(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetch */ + @MustBeClosed + fun fetch( + params: ExperimentFetchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetch */ + @MustBeClosed + fun fetch( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetch(experimentId, ExperimentFetchParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/experiment/{experiment_id}/fetch`, but is + * otherwise the same as [ExperimentService.fetchPost]. + */ + @MustBeClosed + fun fetchPost( + experimentId: String, + params: ExperimentFetchPostParams = ExperimentFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetchPost(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see fetchPost */ + @MustBeClosed + fun fetchPost( + params: ExperimentFetchPostParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetchPost */ + @MustBeClosed + fun fetchPost( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetchPost(experimentId, ExperimentFetchPostParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/experiment/{experiment_id}/insert`, but is + * otherwise the same as [ExperimentService.insert]. + */ + @MustBeClosed + fun insert( + experimentId: String, + params: ExperimentInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + insert(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see insert */ + @MustBeClosed + fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/experiment/{experiment_id}/summarize`, but is + * otherwise the same as [ExperimentService.summarize]. + */ + @MustBeClosed + fun summarize( + experimentId: String, + params: ExperimentSummarizeParams = ExperimentSummarizeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + summarize(params.toBuilder().experimentId(experimentId).build(), requestOptions) + + /** @see summarize */ + @MustBeClosed + fun summarize( + params: ExperimentSummarizeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see summarize */ + @MustBeClosed + fun summarize( + experimentId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + summarize(experimentId, ExperimentSummarizeParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceImpl.kt index a150dcf2..a225be9e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Experiment import com.braintrustdata.api.models.ExperimentCreateParams import com.braintrustdata.api.models.ExperimentDeleteParams @@ -16,6 +24,7 @@ import com.braintrustdata.api.models.ExperimentFetchParams import com.braintrustdata.api.models.ExperimentFetchPostParams import com.braintrustdata.api.models.ExperimentInsertParams import com.braintrustdata.api.models.ExperimentListPage +import com.braintrustdata.api.models.ExperimentListPageResponse import com.braintrustdata.api.models.ExperimentListParams import com.braintrustdata.api.models.ExperimentRetrieveParams import com.braintrustdata.api.models.ExperimentSummarizeParams @@ -24,322 +33,407 @@ import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchExperimentEventsResponse import com.braintrustdata.api.models.InsertEventsResponse import com.braintrustdata.api.models.SummarizeExperimentResponse -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ExperimentServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : ExperimentService { +class ExperimentServiceImpl internal constructor(private val clientOptions: ClientOptions) : + ExperimentService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ExperimentService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ExperimentService.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ExperimentService = + ExperimentServiceImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new experiment. If there is an existing experiment in the project with the same name - * as the one specified in the request, will return the existing experiment unmodified - */ override fun create( params: ExperimentCreateParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Experiment = + // post /v1/experiment + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve( + params: ExperimentRetrieveParams, + requestOptions: RequestOptions, + ): Experiment = + // get /v1/experiment/{experiment_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update( + params: ExperimentUpdateParams, + requestOptions: RequestOptions, + ): Experiment = + // patch /v1/experiment/{experiment_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: ExperimentListParams, + requestOptions: RequestOptions, + ): ExperimentListPage = + // get /v1/experiment + withRawResponse().list(params, requestOptions).parse() + + override fun delete( + params: ExperimentDeleteParams, + requestOptions: RequestOptions, + ): Experiment = + // delete /v1/experiment/{experiment_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun feedback( + params: ExperimentFeedbackParams, + requestOptions: RequestOptions, + ): FeedbackResponseSchema = + // post /v1/experiment/{experiment_id}/feedback + withRawResponse().feedback(params, requestOptions).parse() + + override fun fetch( + params: ExperimentFetchParams, + requestOptions: RequestOptions, + ): FetchExperimentEventsResponse = + // get /v1/experiment/{experiment_id}/fetch + withRawResponse().fetch(params, requestOptions).parse() + + override fun fetchPost( + params: ExperimentFetchPostParams, + requestOptions: RequestOptions, + ): FetchExperimentEventsResponse = + // post /v1/experiment/{experiment_id}/fetch + withRawResponse().fetchPost(params, requestOptions).parse() + + override fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions, + ): InsertEventsResponse = + // post /v1/experiment/{experiment_id}/insert + withRawResponse().insert(params, requestOptions).parse() + + override fun summarize( + params: ExperimentSummarizeParams, + requestOptions: RequestOptions, + ): SummarizeExperimentResponse = + // get /v1/experiment/{experiment_id}/summarize + withRawResponse().summarize(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ExperimentService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ExperimentService.WithRawResponse = + ExperimentServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ExperimentCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get an experiment object by its id */ - override fun retrieve( - params: ExperimentRetrieveParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun retrieve( + params: ExperimentRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update an experiment object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update( - params: ExperimentUpdateParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "experiment", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun update( + params: ExperimentUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all experiments. The experiments are sorted by creation date, with the most - * recently-created experiments coming first - */ - override fun list( - params: ExperimentListParams, - requestOptions: RequestOptions - ): ExperimentListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun list( + params: ExperimentListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { ExperimentListPage.of(this, params, it) } + .let { + ExperimentListPage.builder() + .service(ExperimentServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete an experiment object by its id */ - override fun delete( - params: ExperimentDeleteParams, - requestOptions: RequestOptions - ): Experiment { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "experiment", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun delete( + params: ExperimentDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val feedbackHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val feedbackHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Log feedback for a set of experiment events */ - override fun feedback( - params: ExperimentFeedbackParams, - requestOptions: RequestOptions - ): FeedbackResponseSchema { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment", params.getPathParam(0), "feedback") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { feedbackHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun feedback( + params: ExperimentFeedbackParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "feedback") + .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 { feedbackHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in an experiment. Equivalent to the POST form of the same path, but with the - * parameters in the URL query rather than in the request body - */ - override fun fetch( - params: ExperimentFetchParams, - requestOptions: RequestOptions - ): FetchExperimentEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { fetchHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun fetch( + params: ExperimentFetchParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "fetch") + .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 { fetchHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchPostHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchPostHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in an experiment. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query - */ - override fun fetchPost( - params: ExperimentFetchPostParams, - requestOptions: RequestOptions - ): FetchExperimentEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { fetchPostHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun fetchPost( + params: ExperimentFetchPostParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "fetch") + .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 { fetchPostHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val insertHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val insertHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Insert a set of events into the experiment */ - override fun insert( - params: ExperimentInsertParams, - requestOptions: RequestOptions - ): InsertEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "experiment", params.getPathParam(0), "insert") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { insertHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun insert( + params: ExperimentInsertParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "insert") + .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 { insertHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val summarizeHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val summarizeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Summarize experiment */ - override fun summarize( - params: ExperimentSummarizeParams, - requestOptions: RequestOptions - ): SummarizeExperimentResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "experiment", params.getPathParam(0), "summarize") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { summarizeHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun summarize( + params: ExperimentSummarizeParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("experimentId", params.experimentId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "experiment", params._pathParam(0), "summarize") + .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 { summarizeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionService.kt index aa80d44b..1f21f265 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Function import com.braintrustdata.api.models.FunctionCreateParams import com.braintrustdata.api.models.FunctionDeleteParams @@ -15,54 +15,116 @@ import com.braintrustdata.api.models.FunctionListParams import com.braintrustdata.api.models.FunctionReplaceParams import com.braintrustdata.api.models.FunctionRetrieveParams import com.braintrustdata.api.models.FunctionUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface FunctionService { + /** + * 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: (ClientOptions.Builder) -> Unit): FunctionService + /** * Create a new function. If there is an existing function in the project with the same slug as * the one specified in the request, will return the existing function unmodified */ fun create( params: FunctionCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function /** Get a function object by its id */ + fun retrieve( + functionId: String, + params: FunctionRetrieveParams = FunctionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Function = retrieve(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: FunctionRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + /** @see retrieve */ + fun retrieve(functionId: String, requestOptions: RequestOptions): Function = + retrieve(functionId, FunctionRetrieveParams.none(), requestOptions) + /** * Partially update a function object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + functionId: String, + params: FunctionUpdateParams = FunctionUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Function = update(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see update */ fun update( params: FunctionUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + /** @see update */ + fun update(functionId: String, requestOptions: RequestOptions): Function = + update(functionId, FunctionUpdateParams.none(), requestOptions) + /** * List out all functions. The functions are sorted by creation date, with the most * recently-created functions coming first */ fun list( - params: FunctionListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: FunctionListParams = FunctionListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): FunctionListPage + /** @see list */ + fun list(requestOptions: RequestOptions): FunctionListPage = + list(FunctionListParams.none(), requestOptions) + /** Delete a function object by its id */ + fun delete( + functionId: String, + params: FunctionDeleteParams = FunctionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Function = delete(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see delete */ fun delete( params: FunctionDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + /** @see delete */ + fun delete(functionId: String, requestOptions: RequestOptions): Function = + delete(functionId, FunctionDeleteParams.none(), requestOptions) + /** Invoke a function. */ + fun invoke( + functionId: String, + params: FunctionInvokeParams = FunctionInvokeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FunctionInvokeResponse? = + invoke(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see invoke */ fun invoke( params: FunctionInvokeParams, - requestOptions: RequestOptions = RequestOptions.none() - ): FunctionInvokeResponse + requestOptions: RequestOptions = RequestOptions.none(), + ): FunctionInvokeResponse? + + /** @see invoke */ + fun invoke(functionId: String, requestOptions: RequestOptions): FunctionInvokeResponse? = + invoke(functionId, FunctionInvokeParams.none(), requestOptions) /** * Create or replace function. If there is an existing function in the project with the same @@ -71,6 +133,154 @@ interface FunctionService { */ fun replace( params: FunctionReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Function + + /** A view of [FunctionService] 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: (ClientOptions.Builder) -> Unit): FunctionService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/function`, but is otherwise the same as + * [FunctionService.create]. + */ + @MustBeClosed + fun create( + params: FunctionCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/function/{function_id}`, but is otherwise the + * same as [FunctionService.retrieve]. + */ + @MustBeClosed + fun retrieve( + functionId: String, + params: FunctionRetrieveParams = FunctionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: FunctionRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + functionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(functionId, FunctionRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/function/{function_id}`, but is otherwise the + * same as [FunctionService.update]. + */ + @MustBeClosed + fun update( + functionId: String, + params: FunctionUpdateParams = FunctionUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: FunctionUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update(functionId: String, requestOptions: RequestOptions): HttpResponseFor = + update(functionId, FunctionUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/function`, but is otherwise the same as + * [FunctionService.list]. + */ + @MustBeClosed + fun list( + params: FunctionListParams = FunctionListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(FunctionListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/function/{function_id}`, but is otherwise the + * same as [FunctionService.delete]. + */ + @MustBeClosed + fun delete( + functionId: String, + params: FunctionDeleteParams = FunctionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: FunctionDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(functionId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(functionId, FunctionDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/function/{function_id}/invoke`, but is + * otherwise the same as [FunctionService.invoke]. + */ + @MustBeClosed + fun invoke( + functionId: String, + params: FunctionInvokeParams = FunctionInvokeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + invoke(params.toBuilder().functionId(functionId).build(), requestOptions) + + /** @see invoke */ + @MustBeClosed + fun invoke( + params: FunctionInvokeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see invoke */ + @MustBeClosed + fun invoke( + functionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + invoke(functionId, FunctionInvokeParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/function`, but is otherwise the same as + * [FunctionService.replace]. + */ + @MustBeClosed + fun replace( + params: FunctionReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceImpl.kt index ef3824db..d10f9370 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceImpl.kt @@ -4,228 +4,303 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Function import com.braintrustdata.api.models.FunctionCreateParams import com.braintrustdata.api.models.FunctionDeleteParams import com.braintrustdata.api.models.FunctionInvokeParams import com.braintrustdata.api.models.FunctionInvokeResponse import com.braintrustdata.api.models.FunctionListPage +import com.braintrustdata.api.models.FunctionListPageResponse import com.braintrustdata.api.models.FunctionListParams import com.braintrustdata.api.models.FunctionReplaceParams import com.braintrustdata.api.models.FunctionRetrieveParams import com.braintrustdata.api.models.FunctionUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class FunctionServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : FunctionService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new function. If there is an existing function in the project with the same slug as - * the one specified in the request, will return the existing function unmodified - */ - override fun create(params: FunctionCreateParams, requestOptions: RequestOptions): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "function") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() - } - } - } + +class FunctionServiceImpl internal constructor(private val clientOptions: ClientOptions) : + FunctionService { + + private val withRawResponse: FunctionService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withRawResponse(): FunctionService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): FunctionService = + FunctionServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: FunctionCreateParams, requestOptions: RequestOptions): Function = + // post /v1/function + withRawResponse().create(params, requestOptions).parse() - /** Get a function object by its id */ override fun retrieve( params: FunctionRetrieveParams, - requestOptions: RequestOptions - ): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "function", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Function = + // get /v1/function/{function_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: FunctionUpdateParams, requestOptions: RequestOptions): Function = + // patch /v1/function/{function_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: FunctionListParams, + requestOptions: RequestOptions, + ): FunctionListPage = + // get /v1/function + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: FunctionDeleteParams, requestOptions: RequestOptions): Function = + // delete /v1/function/{function_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun invoke( + params: FunctionInvokeParams, + requestOptions: RequestOptions, + ): FunctionInvokeResponse? = + // post /v1/function/{function_id}/invoke + withRawResponse().invoke(params, requestOptions).parse() + + override fun replace(params: FunctionReplaceParams, requestOptions: RequestOptions): Function = + // put /v1/function + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + FunctionService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): FunctionService.WithRawResponse = + FunctionServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: FunctionCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a function object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update(params: FunctionUpdateParams, requestOptions: RequestOptions): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "function", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: FunctionRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all functions. The functions are sorted by creation date, with the most - * recently-created functions coming first - */ - override fun list( - params: FunctionListParams, - requestOptions: RequestOptions - ): FunctionListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "function") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun update( + params: FunctionUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { FunctionListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a function object by its id */ - override fun delete(params: FunctionDeleteParams, requestOptions: RequestOptions): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "function", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: FunctionListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + .let { + FunctionListPage.builder() + .service(FunctionServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val invokeHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Invoke a function. */ - override fun invoke( - params: FunctionInvokeParams, - requestOptions: RequestOptions - ): FunctionInvokeResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "function", params.getPathParam(0), "invoke") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response.use { invokeHandler.handle(it) } + override fun delete( + params: FunctionDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace function. If there is an existing function in the project with the same - * slug as the one specified in the request, will replace the existing function with the - * provided fields - */ - override fun replace(params: FunctionReplaceParams, requestOptions: RequestOptions): Function { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "function") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val invokeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun invoke( + params: FunctionInvokeParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("functionId", params.functionId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function", params._pathParam(0), "invoke") + .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 { invokeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it?.validate() + } + } + } + } + + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: FunctionReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "function") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupService.kt index 887eabcc..bda106f3 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Group import com.braintrustdata.api.models.GroupCreateParams import com.braintrustdata.api.models.GroupDeleteParams @@ -13,55 +13,223 @@ import com.braintrustdata.api.models.GroupListParams import com.braintrustdata.api.models.GroupReplaceParams import com.braintrustdata.api.models.GroupRetrieveParams import com.braintrustdata.api.models.GroupUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface GroupService { + /** + * 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: (ClientOptions.Builder) -> Unit): GroupService + /** * Create a new group. If there is an existing group with the same name as the one specified in * the request, will return the existing group unmodified */ fun create( params: GroupCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group /** Get a group object by its id */ + fun retrieve( + groupId: String, + params: GroupRetrieveParams = GroupRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Group = retrieve(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: GroupRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + /** @see retrieve */ + fun retrieve(groupId: String, requestOptions: RequestOptions): Group = + retrieve(groupId, GroupRetrieveParams.none(), requestOptions) + /** * Partially update a group object. Specify the fields to update in the payload. Any object-type * fields will be deep-merged with existing content. Currently we do not support removing fields * or setting them to null. */ + fun update( + groupId: String, + params: GroupUpdateParams = GroupUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Group = update(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see update */ fun update( params: GroupUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + /** @see update */ + fun update(groupId: String, requestOptions: RequestOptions): Group = + update(groupId, GroupUpdateParams.none(), requestOptions) + /** * List out all groups. The groups are sorted by creation date, with the most recently-created * groups coming first */ fun list( - params: GroupListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: GroupListParams = GroupListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): GroupListPage + /** @see list */ + fun list(requestOptions: RequestOptions): GroupListPage = + list(GroupListParams.none(), requestOptions) + /** Delete a group object by its id */ + fun delete( + groupId: String, + params: GroupDeleteParams = GroupDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Group = delete(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see delete */ fun delete( params: GroupDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + /** @see delete */ + fun delete(groupId: String, requestOptions: RequestOptions): Group = + delete(groupId, GroupDeleteParams.none(), requestOptions) + /** * Create or replace group. If there is an existing group with the same name as the one * specified in the request, will replace the existing group with the provided fields */ fun replace( params: GroupReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Group + + /** A view of [GroupService] 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: (ClientOptions.Builder) -> Unit): GroupService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/group`, but is otherwise the same as + * [GroupService.create]. + */ + @MustBeClosed + fun create( + params: GroupCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/group/{group_id}`, but is otherwise the same as + * [GroupService.retrieve]. + */ + @MustBeClosed + fun retrieve( + groupId: String, + params: GroupRetrieveParams = GroupRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: GroupRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(groupId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(groupId, GroupRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/group/{group_id}`, but is otherwise the same + * as [GroupService.update]. + */ + @MustBeClosed + fun update( + groupId: String, + params: GroupUpdateParams = GroupUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: GroupUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update(groupId: String, requestOptions: RequestOptions): HttpResponseFor = + update(groupId, GroupUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/group`, but is otherwise the same as + * [GroupService.list]. + */ + @MustBeClosed + fun list( + params: GroupListParams = GroupListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(GroupListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/group/{group_id}`, but is otherwise the same + * as [GroupService.delete]. + */ + @MustBeClosed + fun delete( + groupId: String, + params: GroupDeleteParams = GroupDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().groupId(groupId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: GroupDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(groupId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(groupId, GroupDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/group`, but is otherwise the same as + * [GroupService.replace]. + */ + @MustBeClosed + fun replace( + params: GroupReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupServiceImpl.kt index 013bad2a..e21235c3 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/GroupServiceImpl.kt @@ -4,195 +4,250 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Group import com.braintrustdata.api.models.GroupCreateParams import com.braintrustdata.api.models.GroupDeleteParams import com.braintrustdata.api.models.GroupListPage +import com.braintrustdata.api.models.GroupListPageResponse import com.braintrustdata.api.models.GroupListParams import com.braintrustdata.api.models.GroupReplaceParams import com.braintrustdata.api.models.GroupRetrieveParams import com.braintrustdata.api.models.GroupUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class GroupServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : GroupService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new group. If there is an existing group with the same name as the one specified in - * the request, will return the existing group unmodified - */ - override fun create(params: GroupCreateParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "group") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + +class GroupServiceImpl internal constructor(private val clientOptions: ClientOptions) : + GroupService { + + private val withRawResponse: GroupService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): GroupService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): GroupService = + GroupServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: GroupCreateParams, requestOptions: RequestOptions): Group = + // post /v1/group + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: GroupRetrieveParams, requestOptions: RequestOptions): Group = + // get /v1/group/{group_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: GroupUpdateParams, requestOptions: RequestOptions): Group = + // patch /v1/group/{group_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list(params: GroupListParams, requestOptions: RequestOptions): GroupListPage = + // get /v1/group + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: GroupDeleteParams, requestOptions: RequestOptions): Group = + // delete /v1/group/{group_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace(params: GroupReplaceParams, requestOptions: RequestOptions): Group = + // put /v1/group + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GroupService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): GroupService.WithRawResponse = + GroupServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: GroupCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get a group object by its id */ - override fun retrieve(params: GroupRetrieveParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "group", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: GroupRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("groupId", params.groupId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a group object. Specify the fields to update in the payload. Any object-type - * fields will be deep-merged with existing content. Currently we do not support removing fields - * or setting them to null. - */ - override fun update(params: GroupUpdateParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "group", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: GroupUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("groupId", params.groupId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * List out all groups. The groups are sorted by creation date, with the most recently-created - * groups coming first - */ - override fun list(params: GroupListParams, requestOptions: RequestOptions): GroupListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "group") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: GroupListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + GroupListPage.builder() + .service(GroupServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { GroupListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a group object by its id */ - override fun delete(params: GroupDeleteParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "group", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: GroupDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("groupId", params.groupId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace group. If there is an existing group with the same name as the one - * specified in the request, will replace the existing group with the provided fields - */ - override fun replace(params: GroupReplaceParams, requestOptions: RequestOptions): Group { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "group") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: GroupReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "group") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationService.kt index a0146c74..7b0f9149 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Organization import com.braintrustdata.api.models.OrganizationDeleteParams import com.braintrustdata.api.models.OrganizationListPage @@ -12,39 +12,205 @@ import com.braintrustdata.api.models.OrganizationListParams import com.braintrustdata.api.models.OrganizationRetrieveParams import com.braintrustdata.api.models.OrganizationUpdateParams import com.braintrustdata.api.services.blocking.organizations.MemberService +import com.google.errorprone.annotations.MustBeClosed interface OrganizationService { + /** + * 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: (ClientOptions.Builder) -> Unit): OrganizationService + fun members(): MemberService /** Get an organization object by its id */ + fun retrieve( + organizationId: String, + params: OrganizationRetrieveParams = OrganizationRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Organization = + retrieve(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: OrganizationRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Organization + /** @see retrieve */ + fun retrieve(organizationId: String, requestOptions: RequestOptions): Organization = + retrieve(organizationId, OrganizationRetrieveParams.none(), requestOptions) + /** * Partially update an organization object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + organizationId: String, + params: OrganizationUpdateParams = OrganizationUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Organization = + update(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see update */ fun update( params: OrganizationUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Organization + /** @see update */ + fun update(organizationId: String, requestOptions: RequestOptions): Organization = + update(organizationId, OrganizationUpdateParams.none(), requestOptions) + /** * List out all organizations. The organizations are sorted by creation date, with the most * recently-created organizations coming first */ fun list( - params: OrganizationListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: OrganizationListParams = OrganizationListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): OrganizationListPage + /** @see list */ + fun list(requestOptions: RequestOptions): OrganizationListPage = + list(OrganizationListParams.none(), requestOptions) + /** Delete an organization object by its id */ + fun delete( + organizationId: String, + params: OrganizationDeleteParams = OrganizationDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Organization = + delete(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see delete */ fun delete( params: OrganizationDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Organization + + /** @see delete */ + fun delete(organizationId: String, requestOptions: RequestOptions): Organization = + delete(organizationId, OrganizationDeleteParams.none(), requestOptions) + + /** + * A view of [OrganizationService] 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: (ClientOptions.Builder) -> Unit + ): OrganizationService.WithRawResponse + + fun members(): MemberService.WithRawResponse + + /** + * Returns a raw HTTP response for `get /v1/organization/{organization_id}`, but is + * otherwise the same as [OrganizationService.retrieve]. + */ + @MustBeClosed + fun retrieve( + organizationId: String, + params: OrganizationRetrieveParams = OrganizationRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: OrganizationRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + organizationId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(organizationId, OrganizationRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/organization/{organization_id}`, but is + * otherwise the same as [OrganizationService.update]. + */ + @MustBeClosed + fun update( + organizationId: String, + params: OrganizationUpdateParams = OrganizationUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: OrganizationUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update( + organizationId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(organizationId, OrganizationUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/organization`, but is otherwise the same as + * [OrganizationService.list]. + */ + @MustBeClosed + fun list( + params: OrganizationListParams = OrganizationListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(OrganizationListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/organization/{organization_id}`, but is + * otherwise the same as [OrganizationService.delete]. + */ + @MustBeClosed + fun delete( + organizationId: String, + params: OrganizationDeleteParams = OrganizationDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().organizationId(organizationId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: OrganizationDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete( + organizationId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(organizationId, OrganizationDeleteParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceImpl.kt index 26ed5872..d1b5a199 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceImpl.kt @@ -4,154 +4,215 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Organization import com.braintrustdata.api.models.OrganizationDeleteParams import com.braintrustdata.api.models.OrganizationListPage +import com.braintrustdata.api.models.OrganizationListPageResponse import com.braintrustdata.api.models.OrganizationListParams import com.braintrustdata.api.models.OrganizationRetrieveParams import com.braintrustdata.api.models.OrganizationUpdateParams import com.braintrustdata.api.services.blocking.organizations.MemberService import com.braintrustdata.api.services.blocking.organizations.MemberServiceImpl -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class OrganizationServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : OrganizationService { +class OrganizationServiceImpl internal constructor(private val clientOptions: ClientOptions) : + OrganizationService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: OrganizationService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } private val members: MemberService by lazy { MemberServiceImpl(clientOptions) } - override fun members(): MemberService = members + override fun withRawResponse(): OrganizationService.WithRawResponse = withRawResponse - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): OrganizationService = + OrganizationServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun members(): MemberService = members - /** Get an organization object by its id */ override fun retrieve( params: OrganizationRetrieveParams, - requestOptions: RequestOptions - ): Organization { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "organization", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): Organization = + // get /v1/organization/{organization_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update( + params: OrganizationUpdateParams, + requestOptions: RequestOptions, + ): Organization = + // patch /v1/organization/{organization_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: OrganizationListParams, + requestOptions: RequestOptions, + ): OrganizationListPage = + // get /v1/organization + withRawResponse().list(params, requestOptions).parse() + + override fun delete( + params: OrganizationDeleteParams, + requestOptions: RequestOptions, + ): Organization = + // delete /v1/organization/{organization_id} + withRawResponse().delete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + OrganizationService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + private val members: MemberService.WithRawResponse by lazy { + MemberServiceImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): OrganizationService.WithRawResponse = + OrganizationServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + override fun members(): MemberService.WithRawResponse = members + + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: OrganizationRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("organizationId", params.organizationId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update an organization object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update( - params: OrganizationUpdateParams, - requestOptions: RequestOptions - ): Organization { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "organization", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun update( + params: OrganizationUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("organizationId", params.organizationId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all organizations. The organizations are sorted by creation date, with the most - * recently-created organizations coming first - */ - override fun list( - params: OrganizationListParams, - requestOptions: RequestOptions - ): OrganizationListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "organization") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun list( + params: OrganizationListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + OrganizationListPage.builder() + .service(OrganizationServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { OrganizationListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete an organization object by its id */ - override fun delete( - params: OrganizationDeleteParams, - requestOptions: RequestOptions - ): Organization { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "organization", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun delete( + params: OrganizationDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("organizationId", params.organizationId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreService.kt index c47694a9..3547cba6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.ProjectScore import com.braintrustdata.api.models.ProjectScoreCreateParams import com.braintrustdata.api.models.ProjectScoreDeleteParams @@ -13,9 +13,22 @@ import com.braintrustdata.api.models.ProjectScoreListParams import com.braintrustdata.api.models.ProjectScoreReplaceParams import com.braintrustdata.api.models.ProjectScoreRetrieveParams import com.braintrustdata.api.models.ProjectScoreUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface ProjectScoreService { + /** + * 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: (ClientOptions.Builder) -> Unit): ProjectScoreService + /** * Create a new project_score. If there is an existing project_score in the project with the * same name as the one specified in the request, will return the existing project_score @@ -23,40 +36,80 @@ interface ProjectScoreService { */ fun create( params: ProjectScoreCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore /** Get a project_score object by its id */ + fun retrieve( + projectScoreId: String, + params: ProjectScoreRetrieveParams = ProjectScoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectScore = + retrieve(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: ProjectScoreRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + /** @see retrieve */ + fun retrieve(projectScoreId: String, requestOptions: RequestOptions): ProjectScore = + retrieve(projectScoreId, ProjectScoreRetrieveParams.none(), requestOptions) + /** * Partially update a project_score object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + projectScoreId: String, + params: ProjectScoreUpdateParams = ProjectScoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectScore = + update(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see update */ fun update( params: ProjectScoreUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + /** @see update */ + fun update(projectScoreId: String, requestOptions: RequestOptions): ProjectScore = + update(projectScoreId, ProjectScoreUpdateParams.none(), requestOptions) + /** * List out all project_scores. The project_scores are sorted by creation date, with the most * recently-created project_scores coming first */ fun list( - params: ProjectScoreListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ProjectScoreListParams = ProjectScoreListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScoreListPage + /** @see list */ + fun list(requestOptions: RequestOptions): ProjectScoreListPage = + list(ProjectScoreListParams.none(), requestOptions) + /** Delete a project_score object by its id */ + fun delete( + projectScoreId: String, + params: ProjectScoreDeleteParams = ProjectScoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectScore = + delete(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see delete */ fun delete( params: ProjectScoreDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + /** @see delete */ + fun delete(projectScoreId: String, requestOptions: RequestOptions): ProjectScore = + delete(projectScoreId, ProjectScoreDeleteParams.none(), requestOptions) + /** * Create or replace project_score. If there is an existing project_score in the project with * the same name as the one specified in the request, will replace the existing project_score @@ -64,6 +117,137 @@ interface ProjectScoreService { */ fun replace( params: ProjectScoreReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectScore + + /** + * A view of [ProjectScoreService] 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: (ClientOptions.Builder) -> Unit + ): ProjectScoreService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project_score`, but is otherwise the same as + * [ProjectScoreService.create]. + */ + @MustBeClosed + fun create( + params: ProjectScoreCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project_score/{project_score_id}`, but is + * otherwise the same as [ProjectScoreService.retrieve]. + */ + @MustBeClosed + fun retrieve( + projectScoreId: String, + params: ProjectScoreRetrieveParams = ProjectScoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: ProjectScoreRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + projectScoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(projectScoreId, ProjectScoreRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/project_score/{project_score_id}`, but is + * otherwise the same as [ProjectScoreService.update]. + */ + @MustBeClosed + fun update( + projectScoreId: String, + params: ProjectScoreUpdateParams = ProjectScoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: ProjectScoreUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update( + projectScoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(projectScoreId, ProjectScoreUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/project_score`, but is otherwise the same as + * [ProjectScoreService.list]. + */ + @MustBeClosed + fun list( + params: ProjectScoreListParams = ProjectScoreListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ProjectScoreListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/project_score/{project_score_id}`, but is + * otherwise the same as [ProjectScoreService.delete]. + */ + @MustBeClosed + fun delete( + projectScoreId: String, + params: ProjectScoreDeleteParams = ProjectScoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().projectScoreId(projectScoreId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: ProjectScoreDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete( + projectScoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(projectScoreId, ProjectScoreDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/project_score`, but is otherwise the same as + * [ProjectScoreService.replace]. + */ + @MustBeClosed + fun replace( + params: ProjectScoreReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceImpl.kt index ec231f82..0aa76a56 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceImpl.kt @@ -4,216 +4,275 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.ProjectScore import com.braintrustdata.api.models.ProjectScoreCreateParams import com.braintrustdata.api.models.ProjectScoreDeleteParams import com.braintrustdata.api.models.ProjectScoreListPage +import com.braintrustdata.api.models.ProjectScoreListPageResponse import com.braintrustdata.api.models.ProjectScoreListParams import com.braintrustdata.api.models.ProjectScoreReplaceParams import com.braintrustdata.api.models.ProjectScoreRetrieveParams import com.braintrustdata.api.models.ProjectScoreUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class ProjectScoreServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : ProjectScoreService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new project_score. If there is an existing project_score in the project with the - * same name as the one specified in the request, will return the existing project_score - * unmodified - */ + +class ProjectScoreServiceImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectScoreService { + + private val withRawResponse: ProjectScoreService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ProjectScoreService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ProjectScoreService = + ProjectScoreServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + override fun create( params: ProjectScoreCreateParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_score") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): ProjectScore = + // post /v1/project_score + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve( + params: ProjectScoreRetrieveParams, + requestOptions: RequestOptions, + ): ProjectScore = + // get /v1/project_score/{project_score_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update( + params: ProjectScoreUpdateParams, + requestOptions: RequestOptions, + ): ProjectScore = + // patch /v1/project_score/{project_score_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: ProjectScoreListParams, + requestOptions: RequestOptions, + ): ProjectScoreListPage = + // get /v1/project_score + withRawResponse().list(params, requestOptions).parse() + + override fun delete( + params: ProjectScoreDeleteParams, + requestOptions: RequestOptions, + ): ProjectScore = + // delete /v1/project_score/{project_score_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace( + params: ProjectScoreReplaceParams, + requestOptions: RequestOptions, + ): ProjectScore = + // put /v1/project_score + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectScoreService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ProjectScoreService.WithRawResponse = + ProjectScoreServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ProjectScoreCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get a project_score object by its id */ - override fun retrieve( - params: ProjectScoreRetrieveParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_score", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun retrieve( + params: ProjectScoreRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectScoreId", params.projectScoreId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update a project_score object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update( - params: ProjectScoreUpdateParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "project_score", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun update( + params: ProjectScoreUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectScoreId", params.projectScoreId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all project_scores. The project_scores are sorted by creation date, with the most - * recently-created project_scores coming first - */ - override fun list( - params: ProjectScoreListParams, - requestOptions: RequestOptions - ): ProjectScoreListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_score") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun list( + params: ProjectScoreListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { ProjectScoreListPage.of(this, params, it) } + .let { + ProjectScoreListPage.builder() + .service(ProjectScoreServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete a project_score object by its id */ - override fun delete( - params: ProjectScoreDeleteParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "project_score", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun delete( + params: ProjectScoreDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectScoreId", params.projectScoreId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace project_score. If there is an existing project_score in the project with - * the same name as the one specified in the request, will replace the existing project_score - * with the provided fields - */ - override fun replace( - params: ProjectScoreReplaceParams, - requestOptions: RequestOptions - ): ProjectScore { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "project_score") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun replace( + params: ProjectScoreReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_score") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectService.kt index 8ec2d520..fc4a4711 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Project import com.braintrustdata.api.models.ProjectCreateParams import com.braintrustdata.api.models.ProjectDeleteParams @@ -13,9 +13,22 @@ import com.braintrustdata.api.models.ProjectListParams import com.braintrustdata.api.models.ProjectRetrieveParams import com.braintrustdata.api.models.ProjectUpdateParams import com.braintrustdata.api.services.blocking.projects.LogService +import com.google.errorprone.annotations.MustBeClosed interface ProjectService { + /** + * 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: (ClientOptions.Builder) -> Unit): ProjectService + fun logs(): LogService /** @@ -24,37 +37,184 @@ interface ProjectService { */ fun create( params: ProjectCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project /** Get a project object by its id */ + fun retrieve( + projectId: String, + params: ProjectRetrieveParams = ProjectRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Project = retrieve(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: ProjectRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project + /** @see retrieve */ + fun retrieve(projectId: String, requestOptions: RequestOptions): Project = + retrieve(projectId, ProjectRetrieveParams.none(), requestOptions) + /** * Partially update a project object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + projectId: String, + params: ProjectUpdateParams = ProjectUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Project = update(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see update */ fun update( params: ProjectUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project + /** @see update */ + fun update(projectId: String, requestOptions: RequestOptions): Project = + update(projectId, ProjectUpdateParams.none(), requestOptions) + /** * List out all projects. The projects are sorted by creation date, with the most * recently-created projects coming first */ fun list( - params: ProjectListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ProjectListParams = ProjectListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectListPage + /** @see list */ + fun list(requestOptions: RequestOptions): ProjectListPage = + list(ProjectListParams.none(), requestOptions) + /** Delete a project object by its id */ + fun delete( + projectId: String, + params: ProjectDeleteParams = ProjectDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Project = delete(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see delete */ fun delete( params: ProjectDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Project + + /** @see delete */ + fun delete(projectId: String, requestOptions: RequestOptions): Project = + delete(projectId, ProjectDeleteParams.none(), requestOptions) + + /** A view of [ProjectService] 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: (ClientOptions.Builder) -> Unit): ProjectService.WithRawResponse + + fun logs(): LogService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project`, but is otherwise the same as + * [ProjectService.create]. + */ + @MustBeClosed + fun create( + params: ProjectCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project/{project_id}`, but is otherwise the same + * as [ProjectService.retrieve]. + */ + @MustBeClosed + fun retrieve( + projectId: String, + params: ProjectRetrieveParams = ProjectRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: ProjectRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(projectId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(projectId, ProjectRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/project/{project_id}`, but is otherwise the + * same as [ProjectService.update]. + */ + @MustBeClosed + fun update( + projectId: String, + params: ProjectUpdateParams = ProjectUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: ProjectUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update(projectId: String, requestOptions: RequestOptions): HttpResponseFor = + update(projectId, ProjectUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/project`, but is otherwise the same as + * [ProjectService.list]. + */ + @MustBeClosed + fun list( + params: ProjectListParams = ProjectListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ProjectListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/project/{project_id}`, but is otherwise the + * same as [ProjectService.delete]. + */ + @MustBeClosed + fun delete( + projectId: String, + params: ProjectDeleteParams = ProjectDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: ProjectDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(projectId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(projectId, ProjectDeleteParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceImpl.kt index 1aa43c12..b10c5700 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceImpl.kt @@ -4,172 +4,233 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Project import com.braintrustdata.api.models.ProjectCreateParams import com.braintrustdata.api.models.ProjectDeleteParams import com.braintrustdata.api.models.ProjectListPage +import com.braintrustdata.api.models.ProjectListPageResponse import com.braintrustdata.api.models.ProjectListParams import com.braintrustdata.api.models.ProjectRetrieveParams import com.braintrustdata.api.models.ProjectUpdateParams import com.braintrustdata.api.services.blocking.projects.LogService import com.braintrustdata.api.services.blocking.projects.LogServiceImpl -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ProjectServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : ProjectService { +class ProjectServiceImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ProjectService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } private val logs: LogService by lazy { LogServiceImpl(clientOptions) } + override fun withRawResponse(): ProjectService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ProjectService = + ProjectServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + override fun logs(): LogService = logs - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new project. If there is an existing project with the same name as the one specified - * in the request, will return the existing project unmodified - */ - override fun create(params: ProjectCreateParams, requestOptions: RequestOptions): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun create(params: ProjectCreateParams, requestOptions: RequestOptions): Project = + // post /v1/project + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: ProjectRetrieveParams, requestOptions: RequestOptions): Project = + // get /v1/project/{project_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: ProjectUpdateParams, requestOptions: RequestOptions): Project = + // patch /v1/project/{project_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list(params: ProjectListParams, requestOptions: RequestOptions): ProjectListPage = + // get /v1/project + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: ProjectDeleteParams, requestOptions: RequestOptions): Project = + // delete /v1/project/{project_id} + withRawResponse().delete(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + private val logs: LogService.WithRawResponse by lazy { + LogServiceImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ProjectService.WithRawResponse = + ProjectServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + override fun logs(): LogService.WithRawResponse = logs + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ProjectCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get a project object by its id */ - override fun retrieve(params: ProjectRetrieveParams, requestOptions: RequestOptions): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: ProjectRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a project object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update(params: ProjectUpdateParams, requestOptions: RequestOptions): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "project", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: ProjectUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - /** - * List out all projects. The projects are sorted by creation date, with the most - * recently-created projects coming first - */ - override fun list(params: ProjectListParams, requestOptions: RequestOptions): ProjectListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: ProjectListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } - .let { ProjectListPage.of(this, params, it) } + .let { + ProjectListPage.builder() + .service(ProjectServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a project object by its id */ - override fun delete(params: ProjectDeleteParams, requestOptions: RequestOptions): Project { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "project", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: ProjectDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagService.kt index 9bc7c2f9..064e9f38 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.ProjectTag import com.braintrustdata.api.models.ProjectTagCreateParams import com.braintrustdata.api.models.ProjectTagDeleteParams @@ -13,49 +13,99 @@ import com.braintrustdata.api.models.ProjectTagListParams import com.braintrustdata.api.models.ProjectTagReplaceParams import com.braintrustdata.api.models.ProjectTagRetrieveParams import com.braintrustdata.api.models.ProjectTagUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface ProjectTagService { + /** + * 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: (ClientOptions.Builder) -> Unit): ProjectTagService + /** * Create a new project_tag. If there is an existing project_tag in the project with the same * name as the one specified in the request, will return the existing project_tag unmodified */ fun create( params: ProjectTagCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag /** Get a project_tag object by its id */ + fun retrieve( + projectTagId: String, + params: ProjectTagRetrieveParams = ProjectTagRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectTag = retrieve(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: ProjectTagRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + /** @see retrieve */ + fun retrieve(projectTagId: String, requestOptions: RequestOptions): ProjectTag = + retrieve(projectTagId, ProjectTagRetrieveParams.none(), requestOptions) + /** * Partially update a project_tag object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + projectTagId: String, + params: ProjectTagUpdateParams = ProjectTagUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectTag = update(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see update */ fun update( params: ProjectTagUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + /** @see update */ + fun update(projectTagId: String, requestOptions: RequestOptions): ProjectTag = + update(projectTagId, ProjectTagUpdateParams.none(), requestOptions) + /** * List out all project_tags. The project_tags are sorted by creation date, with the most * recently-created project_tags coming first */ fun list( - params: ProjectTagListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: ProjectTagListParams = ProjectTagListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTagListPage + /** @see list */ + fun list(requestOptions: RequestOptions): ProjectTagListPage = + list(ProjectTagListParams.none(), requestOptions) + /** Delete a project_tag object by its id */ + fun delete( + projectTagId: String, + params: ProjectTagDeleteParams = ProjectTagDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ProjectTag = delete(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see delete */ fun delete( params: ProjectTagDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + /** @see delete */ + fun delete(projectTagId: String, requestOptions: RequestOptions): ProjectTag = + delete(projectTagId, ProjectTagDeleteParams.none(), requestOptions) + /** * Create or replace project_tag. If there is an existing project_tag in the project with the * same name as the one specified in the request, will replace the existing project_tag with the @@ -63,6 +113,135 @@ interface ProjectTagService { */ fun replace( params: ProjectTagReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ProjectTag + + /** A view of [ProjectTagService] 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: (ClientOptions.Builder) -> Unit + ): ProjectTagService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project_tag`, but is otherwise the same as + * [ProjectTagService.create]. + */ + @MustBeClosed + fun create( + params: ProjectTagCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project_tag/{project_tag_id}`, but is otherwise + * the same as [ProjectTagService.retrieve]. + */ + @MustBeClosed + fun retrieve( + projectTagId: String, + params: ProjectTagRetrieveParams = ProjectTagRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: ProjectTagRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + projectTagId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(projectTagId, ProjectTagRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/project_tag/{project_tag_id}`, but is + * otherwise the same as [ProjectTagService.update]. + */ + @MustBeClosed + fun update( + projectTagId: String, + params: ProjectTagUpdateParams = ProjectTagUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: ProjectTagUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update( + projectTagId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(projectTagId, ProjectTagUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/project_tag`, but is otherwise the same as + * [ProjectTagService.list]. + */ + @MustBeClosed + fun list( + params: ProjectTagListParams = ProjectTagListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(ProjectTagListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/project_tag/{project_tag_id}`, but is + * otherwise the same as [ProjectTagService.delete]. + */ + @MustBeClosed + fun delete( + projectTagId: String, + params: ProjectTagDeleteParams = ProjectTagDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().projectTagId(projectTagId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: ProjectTagDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete( + projectTagId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(projectTagId, ProjectTagDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/project_tag`, but is otherwise the same as + * [ProjectTagService.replace]. + */ + @MustBeClosed + fun replace( + params: ProjectTagReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceImpl.kt index 58d595aa..377726f0 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceImpl.kt @@ -4,215 +4,275 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.ProjectTag import com.braintrustdata.api.models.ProjectTagCreateParams import com.braintrustdata.api.models.ProjectTagDeleteParams import com.braintrustdata.api.models.ProjectTagListPage +import com.braintrustdata.api.models.ProjectTagListPageResponse import com.braintrustdata.api.models.ProjectTagListParams import com.braintrustdata.api.models.ProjectTagReplaceParams import com.braintrustdata.api.models.ProjectTagRetrieveParams import com.braintrustdata.api.models.ProjectTagUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class ProjectTagServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : ProjectTagService { +class ProjectTagServiceImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectTagService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: ProjectTagService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ProjectTagService.WithRawResponse = withRawResponse - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ProjectTagService = + ProjectTagServiceImpl(clientOptions.toBuilder().apply(modifier).build()) - /** - * Create a new project_tag. If there is an existing project_tag in the project with the same - * name as the one specified in the request, will return the existing project_tag unmodified - */ override fun create( params: ProjectTagCreateParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_tag") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): ProjectTag = + // post /v1/project_tag + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve( + params: ProjectTagRetrieveParams, + requestOptions: RequestOptions, + ): ProjectTag = + // get /v1/project_tag/{project_tag_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update( + params: ProjectTagUpdateParams, + requestOptions: RequestOptions, + ): ProjectTag = + // patch /v1/project_tag/{project_tag_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: ProjectTagListParams, + requestOptions: RequestOptions, + ): ProjectTagListPage = + // get /v1/project_tag + withRawResponse().list(params, requestOptions).parse() + + override fun delete( + params: ProjectTagDeleteParams, + requestOptions: RequestOptions, + ): ProjectTag = + // delete /v1/project_tag/{project_tag_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace( + params: ProjectTagReplaceParams, + requestOptions: RequestOptions, + ): ProjectTag = + // put /v1/project_tag + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ProjectTagService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ProjectTagService.WithRawResponse = + ProjectTagServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ProjectTagCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Get a project_tag object by its id */ - override fun retrieve( - params: ProjectTagRetrieveParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_tag", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun retrieve( + params: ProjectTagRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectTagId", params.projectTagId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Partially update a project_tag object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update( - params: ProjectTagUpdateParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "project_tag", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun update( + params: ProjectTagUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectTagId", params.projectTagId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all project_tags. The project_tags are sorted by creation date, with the most - * recently-created project_tags coming first - */ - override fun list( - params: ProjectTagListParams, - requestOptions: RequestOptions - ): ProjectTagListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_tag") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun list( + params: ProjectTagListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + ProjectTagListPage.builder() + .service(ProjectTagServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { ProjectTagListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Delete a project_tag object by its id */ - override fun delete( - params: ProjectTagDeleteParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "project_tag", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun delete( + params: ProjectTagDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectTagId", params.projectTagId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Create or replace project_tag. If there is an existing project_tag in the project with the - * same name as the one specified in the request, will replace the existing project_tag with the - * provided fields - */ - override fun replace( - params: ProjectTagReplaceParams, - requestOptions: RequestOptions - ): ProjectTag { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "project_tag") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun replace( + params: ProjectTagReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_tag") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptService.kt index 7a500e3c..f333582a 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Prompt import com.braintrustdata.api.models.PromptCreateParams import com.braintrustdata.api.models.PromptDeleteParams @@ -13,55 +13,223 @@ import com.braintrustdata.api.models.PromptListParams import com.braintrustdata.api.models.PromptReplaceParams import com.braintrustdata.api.models.PromptRetrieveParams import com.braintrustdata.api.models.PromptUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface PromptService { + /** + * 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: (ClientOptions.Builder) -> Unit): PromptService + /** * Create a new prompt. If there is an existing prompt in the project with the same slug as the * one specified in the request, will return the existing prompt unmodified */ fun create( params: PromptCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt /** Get a prompt object by its id */ + fun retrieve( + promptId: String, + params: PromptRetrieveParams = PromptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Prompt = retrieve(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: PromptRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + /** @see retrieve */ + fun retrieve(promptId: String, requestOptions: RequestOptions): Prompt = + retrieve(promptId, PromptRetrieveParams.none(), requestOptions) + /** * Partially update a prompt object. Specify the fields to update in the payload. Any * object-type fields will be deep-merged with existing content. Currently we do not support * removing fields or setting them to null. */ + fun update( + promptId: String, + params: PromptUpdateParams = PromptUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Prompt = update(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see update */ fun update( params: PromptUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + /** @see update */ + fun update(promptId: String, requestOptions: RequestOptions): Prompt = + update(promptId, PromptUpdateParams.none(), requestOptions) + /** * List out all prompts. The prompts are sorted by creation date, with the most recently-created * prompts coming first */ fun list( - params: PromptListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: PromptListParams = PromptListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): PromptListPage + /** @see list */ + fun list(requestOptions: RequestOptions): PromptListPage = + list(PromptListParams.none(), requestOptions) + /** Delete a prompt object by its id */ + fun delete( + promptId: String, + params: PromptDeleteParams = PromptDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Prompt = delete(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see delete */ fun delete( params: PromptDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + /** @see delete */ + fun delete(promptId: String, requestOptions: RequestOptions): Prompt = + delete(promptId, PromptDeleteParams.none(), requestOptions) + /** * Create or replace prompt. If there is an existing prompt in the project with the same slug as * the one specified in the request, will replace the existing prompt with the provided fields */ fun replace( params: PromptReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Prompt + + /** A view of [PromptService] 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: (ClientOptions.Builder) -> Unit): PromptService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/prompt`, but is otherwise the same as + * [PromptService.create]. + */ + @MustBeClosed + fun create( + params: PromptCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/prompt/{prompt_id}`, but is otherwise the same + * as [PromptService.retrieve]. + */ + @MustBeClosed + fun retrieve( + promptId: String, + params: PromptRetrieveParams = PromptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: PromptRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(promptId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(promptId, PromptRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/prompt/{prompt_id}`, but is otherwise the same + * as [PromptService.update]. + */ + @MustBeClosed + fun update( + promptId: String, + params: PromptUpdateParams = PromptUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: PromptUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update(promptId: String, requestOptions: RequestOptions): HttpResponseFor = + update(promptId, PromptUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/prompt`, but is otherwise the same as + * [PromptService.list]. + */ + @MustBeClosed + fun list( + params: PromptListParams = PromptListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(PromptListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/prompt/{prompt_id}`, but is otherwise the + * same as [PromptService.delete]. + */ + @MustBeClosed + fun delete( + promptId: String, + params: PromptDeleteParams = PromptDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().promptId(promptId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: PromptDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(promptId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(promptId, PromptDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/prompt`, but is otherwise the same as + * [PromptService.replace]. + */ + @MustBeClosed + fun replace( + params: PromptReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptServiceImpl.kt index f69ae3bb..ccbd9b63 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/PromptServiceImpl.kt @@ -4,196 +4,250 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Prompt import com.braintrustdata.api.models.PromptCreateParams import com.braintrustdata.api.models.PromptDeleteParams import com.braintrustdata.api.models.PromptListPage +import com.braintrustdata.api.models.PromptListPageResponse import com.braintrustdata.api.models.PromptListParams import com.braintrustdata.api.models.PromptReplaceParams import com.braintrustdata.api.models.PromptRetrieveParams import com.braintrustdata.api.models.PromptUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class PromptServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : PromptService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new prompt. If there is an existing prompt in the project with the same slug as the - * one specified in the request, will return the existing prompt unmodified - */ - override fun create(params: PromptCreateParams, requestOptions: RequestOptions): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "prompt") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + +class PromptServiceImpl internal constructor(private val clientOptions: ClientOptions) : + PromptService { + + private val withRawResponse: PromptService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): PromptService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): PromptService = + PromptServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: PromptCreateParams, requestOptions: RequestOptions): Prompt = + // post /v1/prompt + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: PromptRetrieveParams, requestOptions: RequestOptions): Prompt = + // get /v1/prompt/{prompt_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: PromptUpdateParams, requestOptions: RequestOptions): Prompt = + // patch /v1/prompt/{prompt_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list(params: PromptListParams, requestOptions: RequestOptions): PromptListPage = + // get /v1/prompt + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: PromptDeleteParams, requestOptions: RequestOptions): Prompt = + // delete /v1/prompt/{prompt_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace(params: PromptReplaceParams, requestOptions: RequestOptions): Prompt = + // put /v1/prompt + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + PromptService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): PromptService.WithRawResponse = + PromptServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: PromptCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get a prompt object by its id */ - override fun retrieve(params: PromptRetrieveParams, requestOptions: RequestOptions): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "prompt", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: PromptRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("promptId", params.promptId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a prompt object. Specify the fields to update in the payload. Any - * object-type fields will be deep-merged with existing content. Currently we do not support - * removing fields or setting them to null. - */ - override fun update(params: PromptUpdateParams, requestOptions: RequestOptions): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "prompt", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: PromptUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("promptId", params.promptId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - /** - * List out all prompts. The prompts are sorted by creation date, with the most recently-created - * prompts coming first - */ - override fun list(params: PromptListParams, requestOptions: RequestOptions): PromptListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "prompt") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: PromptListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + PromptListPage.builder() + .service(PromptServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { PromptListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a prompt object by its id */ - override fun delete(params: PromptDeleteParams, requestOptions: RequestOptions): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "prompt", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: PromptDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("promptId", params.promptId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace prompt. If there is an existing prompt in the project with the same slug as - * the one specified in the request, will replace the existing prompt with the provided fields - */ - override fun replace(params: PromptReplaceParams, requestOptions: RequestOptions): Prompt { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "prompt") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: PromptReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "prompt") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleService.kt index db855e06..590d78f3 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.Role import com.braintrustdata.api.models.RoleCreateParams import com.braintrustdata.api.models.RoleDeleteParams @@ -13,55 +13,221 @@ import com.braintrustdata.api.models.RoleListParams import com.braintrustdata.api.models.RoleReplaceParams import com.braintrustdata.api.models.RoleRetrieveParams import com.braintrustdata.api.models.RoleUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface RoleService { + /** + * 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: (ClientOptions.Builder) -> Unit): RoleService + /** * Create a new role. If there is an existing role with the same name as the one specified in * the request, will return the existing role unmodified */ fun create( params: RoleCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role /** Get a role object by its id */ + fun retrieve( + roleId: String, + params: RoleRetrieveParams = RoleRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Role = retrieve(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: RoleRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + /** @see retrieve */ + fun retrieve(roleId: String, requestOptions: RequestOptions): Role = + retrieve(roleId, RoleRetrieveParams.none(), requestOptions) + /** * Partially update a role object. Specify the fields to update in the payload. Any object-type * fields will be deep-merged with existing content. Currently we do not support removing fields * or setting them to null. */ + fun update( + roleId: String, + params: RoleUpdateParams = RoleUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Role = update(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see update */ fun update( params: RoleUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + /** @see update */ + fun update(roleId: String, requestOptions: RequestOptions): Role = + update(roleId, RoleUpdateParams.none(), requestOptions) + /** * List out all roles. The roles are sorted by creation date, with the most recently-created * roles coming first */ fun list( - params: RoleListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: RoleListParams = RoleListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): RoleListPage + /** @see list */ + fun list(requestOptions: RequestOptions): RoleListPage = + list(RoleListParams.none(), requestOptions) + /** Delete a role object by its id */ + fun delete( + roleId: String, + params: RoleDeleteParams = RoleDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Role = delete(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see delete */ fun delete( params: RoleDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + /** @see delete */ + fun delete(roleId: String, requestOptions: RequestOptions): Role = + delete(roleId, RoleDeleteParams.none(), requestOptions) + /** * Create or replace role. If there is an existing role with the same name as the one specified * in the request, will replace the existing role with the provided fields */ fun replace( params: RoleReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): Role + + /** A view of [RoleService] 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: (ClientOptions.Builder) -> Unit): RoleService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/role`, but is otherwise the same as + * [RoleService.create]. + */ + @MustBeClosed + fun create( + params: RoleCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/role/{role_id}`, but is otherwise the same as + * [RoleService.retrieve]. + */ + @MustBeClosed + fun retrieve( + roleId: String, + params: RoleRetrieveParams = RoleRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: RoleRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(roleId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(roleId, RoleRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/role/{role_id}`, but is otherwise the same as + * [RoleService.update]. + */ + @MustBeClosed + fun update( + roleId: String, + params: RoleUpdateParams = RoleUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = update(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: RoleUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update(roleId: String, requestOptions: RequestOptions): HttpResponseFor = + update(roleId, RoleUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/role`, but is otherwise the same as + * [RoleService.list]. + */ + @MustBeClosed + fun list( + params: RoleListParams = RoleListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(RoleListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/role/{role_id}`, but is otherwise the same as + * [RoleService.delete]. + */ + @MustBeClosed + fun delete( + roleId: String, + params: RoleDeleteParams = RoleDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = delete(params.toBuilder().roleId(roleId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: RoleDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete(roleId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(roleId, RoleDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/role`, but is otherwise the same as + * [RoleService.replace]. + */ + @MustBeClosed + fun replace( + params: RoleReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleServiceImpl.kt index 89bd2f20..c872f572 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/RoleServiceImpl.kt @@ -4,195 +4,249 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.Role import com.braintrustdata.api.models.RoleCreateParams import com.braintrustdata.api.models.RoleDeleteParams import com.braintrustdata.api.models.RoleListPage +import com.braintrustdata.api.models.RoleListPageResponse import com.braintrustdata.api.models.RoleListParams import com.braintrustdata.api.models.RoleReplaceParams import com.braintrustdata.api.models.RoleRetrieveParams import com.braintrustdata.api.models.RoleUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class RoleServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : RoleService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new role. If there is an existing role with the same name as the one specified in - * the request, will return the existing role unmodified - */ - override fun create(params: RoleCreateParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "role") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + +class RoleServiceImpl internal constructor(private val clientOptions: ClientOptions) : RoleService { + + private val withRawResponse: RoleService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): RoleService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): RoleService = + RoleServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: RoleCreateParams, requestOptions: RequestOptions): Role = + // post /v1/role + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: RoleRetrieveParams, requestOptions: RequestOptions): Role = + // get /v1/role/{role_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: RoleUpdateParams, requestOptions: RequestOptions): Role = + // patch /v1/role/{role_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list(params: RoleListParams, requestOptions: RequestOptions): RoleListPage = + // get /v1/role + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: RoleDeleteParams, requestOptions: RequestOptions): Role = + // delete /v1/role/{role_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace(params: RoleReplaceParams, requestOptions: RequestOptions): Role = + // put /v1/role + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + RoleService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): RoleService.WithRawResponse = + RoleServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: RoleCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get a role object by its id */ - override fun retrieve(params: RoleRetrieveParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "role", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: RoleRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("roleId", params.roleId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a role object. Specify the fields to update in the payload. Any object-type - * fields will be deep-merged with existing content. Currently we do not support removing fields - * or setting them to null. - */ - override fun update(params: RoleUpdateParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "role", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: RoleUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("roleId", params.roleId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * List out all roles. The roles are sorted by creation date, with the most recently-created - * roles coming first - */ - override fun list(params: RoleListParams, requestOptions: RequestOptions): RoleListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "role") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: RoleListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + RoleListPage.builder() + .service(RoleServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { RoleListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a role object by its id */ - override fun delete(params: RoleDeleteParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "role", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .apply { params.getBody()?.also { body(json(clientOptions.jsonMapper, it)) } } - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: RoleDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("roleId", params.roleId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace role. If there is an existing role with the same name as the one specified - * in the request, will replace the existing role with the provided fields - */ - override fun replace(params: RoleReplaceParams, requestOptions: RequestOptions): Role { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "role") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: RoleReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "role") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/SpanIframeService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/SpanIframeService.kt new file mode 100644 index 00000000..86a872e6 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/SpanIframeService.kt @@ -0,0 +1,246 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.blocking + +import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.models.SpanIFrame +import com.braintrustdata.api.models.SpanIframeCreateParams +import com.braintrustdata.api.models.SpanIframeDeleteParams +import com.braintrustdata.api.models.SpanIframeListPage +import com.braintrustdata.api.models.SpanIframeListParams +import com.braintrustdata.api.models.SpanIframeReplaceParams +import com.braintrustdata.api.models.SpanIframeRetrieveParams +import com.braintrustdata.api.models.SpanIframeUpdateParams +import com.google.errorprone.annotations.MustBeClosed + +interface SpanIframeService { + + /** + * 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: (ClientOptions.Builder) -> Unit): SpanIframeService + + /** + * Create a new span_iframe. If there is an existing span_iframe with the same name as the one + * specified in the request, will return the existing span_iframe unmodified + */ + fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** Get a span_iframe object by its id */ + fun retrieve( + spanIframeId: String, + params: SpanIframeRetrieveParams = SpanIframeRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame = retrieve(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see retrieve */ + fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** @see retrieve */ + fun retrieve(spanIframeId: String, requestOptions: RequestOptions): SpanIFrame = + retrieve(spanIframeId, SpanIframeRetrieveParams.none(), requestOptions) + + /** + * Partially update a span_iframe object. Specify the fields to update in the payload. Any + * object-type fields will be deep-merged with existing content. Currently we do not support + * removing fields or setting them to null. + */ + fun update( + spanIframeId: String, + params: SpanIframeUpdateParams = SpanIframeUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame = update(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see update */ + fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** @see update */ + fun update(spanIframeId: String, requestOptions: RequestOptions): SpanIFrame = + update(spanIframeId, SpanIframeUpdateParams.none(), requestOptions) + + /** + * List out all span_iframes. The span_iframes are sorted by creation date, with the most + * recently-created span_iframes coming first + */ + fun list( + params: SpanIframeListParams = SpanIframeListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIframeListPage + + /** @see list */ + fun list(requestOptions: RequestOptions): SpanIframeListPage = + list(SpanIframeListParams.none(), requestOptions) + + /** Delete a span_iframe object by its id */ + fun delete( + spanIframeId: String, + params: SpanIframeDeleteParams = SpanIframeDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame = delete(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see delete */ + fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** @see delete */ + fun delete(spanIframeId: String, requestOptions: RequestOptions): SpanIFrame = + delete(spanIframeId, SpanIframeDeleteParams.none(), requestOptions) + + /** + * Create or replace span_iframe. If there is an existing span_iframe with the same name as the + * one specified in the request, will replace the existing span_iframe with the provided fields + */ + fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SpanIFrame + + /** A view of [SpanIframeService] 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: (ClientOptions.Builder) -> Unit + ): SpanIframeService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/span_iframe`, but is otherwise the same as + * [SpanIframeService.create]. + */ + @MustBeClosed + fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/span_iframe/{span_iframe_id}`, but is otherwise + * the same as [SpanIframeService.retrieve]. + */ + @MustBeClosed + fun retrieve( + spanIframeId: String, + params: SpanIframeRetrieveParams = SpanIframeRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + spanIframeId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(spanIframeId, SpanIframeRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `patch /v1/span_iframe/{span_iframe_id}`, but is + * otherwise the same as [SpanIframeService.update]. + */ + @MustBeClosed + fun update( + spanIframeId: String, + params: SpanIframeUpdateParams = SpanIframeUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update( + spanIframeId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(spanIframeId, SpanIframeUpdateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/span_iframe`, but is otherwise the same as + * [SpanIframeService.list]. + */ + @MustBeClosed + fun list( + params: SpanIframeListParams = SpanIframeListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(SpanIframeListParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/span_iframe/{span_iframe_id}`, but is + * otherwise the same as [SpanIframeService.delete]. + */ + @MustBeClosed + fun delete( + spanIframeId: String, + params: SpanIframeDeleteParams = SpanIframeDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().spanIframeId(spanIframeId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see delete */ + @MustBeClosed + fun delete( + spanIframeId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(spanIframeId, SpanIframeDeleteParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `put /v1/span_iframe`, but is otherwise the same as + * [SpanIframeService.replace]. + */ + @MustBeClosed + fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/SpanIframeServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/SpanIframeServiceImpl.kt new file mode 100644 index 00000000..af799216 --- /dev/null +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/SpanIframeServiceImpl.kt @@ -0,0 +1,278 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.blocking + +import com.braintrustdata.api.core.ClientOptions +import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler +import com.braintrustdata.api.core.http.HttpMethod +import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse +import com.braintrustdata.api.core.http.HttpResponse.Handler +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare +import com.braintrustdata.api.models.SpanIFrame +import com.braintrustdata.api.models.SpanIframeCreateParams +import com.braintrustdata.api.models.SpanIframeDeleteParams +import com.braintrustdata.api.models.SpanIframeListPage +import com.braintrustdata.api.models.SpanIframeListPageResponse +import com.braintrustdata.api.models.SpanIframeListParams +import com.braintrustdata.api.models.SpanIframeReplaceParams +import com.braintrustdata.api.models.SpanIframeRetrieveParams +import com.braintrustdata.api.models.SpanIframeUpdateParams + +class SpanIframeServiceImpl internal constructor(private val clientOptions: ClientOptions) : + SpanIframeService { + + private val withRawResponse: SpanIframeService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): SpanIframeService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): SpanIframeService = + SpanIframeServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // post /v1/span_iframe + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // get /v1/span_iframe/{span_iframe_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // patch /v1/span_iframe/{span_iframe_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list( + params: SpanIframeListParams, + requestOptions: RequestOptions, + ): SpanIframeListPage = + // get /v1/span_iframe + withRawResponse().list(params, requestOptions).parse() + + override fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // delete /v1/span_iframe/{span_iframe_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions, + ): SpanIFrame = + // put /v1/span_iframe + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + SpanIframeService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): SpanIframeService.WithRawResponse = + SpanIframeServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: SpanIframeCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: SpanIframeRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("spanIframeId", params.spanIframeId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: SpanIframeUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("spanIframeId", params.spanIframeId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: SpanIframeListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + SpanIframeListPage.builder() + .service(SpanIframeServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } + } + + private val deleteHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: SpanIframeDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("spanIframeId", params.spanIframeId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe", params._pathParam(0)) + .apply { params._body()?.let { 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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val replaceHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: SpanIframeReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "span_iframe") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } +} diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelService.kt index c0972232..fe3fe45b 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelService.kt @@ -1,17 +1,60 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.TopLevelHelloWorldParams +import com.google.errorprone.annotations.MustBeClosed interface TopLevelService { + /** + * 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: (ClientOptions.Builder) -> Unit): TopLevelService + /** Default endpoint. Simply replies with 'Hello, World!'. Authorization is not required */ fun helloWorld( - params: TopLevelHelloWorldParams, - requestOptions: RequestOptions = RequestOptions.none() + params: TopLevelHelloWorldParams = TopLevelHelloWorldParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): String + + /** @see helloWorld */ + fun helloWorld(requestOptions: RequestOptions): String = + helloWorld(TopLevelHelloWorldParams.none(), requestOptions) + + /** A view of [TopLevelService] 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: (ClientOptions.Builder) -> Unit): TopLevelService.WithRawResponse + + /** + * Returns a raw HTTP response for `get /v1`, but is otherwise the same as + * [TopLevelService.helloWorld]. + */ + @MustBeClosed + fun helloWorld( + params: TopLevelHelloWorldParams = TopLevelHelloWorldParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see helloWorld */ + @MustBeClosed + fun helloWorld(requestOptions: RequestOptions): HttpResponseFor = + helloWorld(TopLevelHelloWorldParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceImpl.kt index 631eac96..e6cbc82f 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceImpl.kt @@ -4,40 +4,68 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.stringHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.TopLevelHelloWorldParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.stringHandler -import com.braintrustdata.api.services.withErrorHandler -class TopLevelServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : TopLevelService { +class TopLevelServiceImpl internal constructor(private val clientOptions: ClientOptions) : + TopLevelService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: TopLevelService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): TopLevelService.WithRawResponse = withRawResponse - private val helloWorldHandler: Handler = stringHandler().withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): TopLevelService = + TopLevelServiceImpl(clientOptions.toBuilder().apply(modifier).build()) - /** Default endpoint. Simply replies with 'Hello, World!'. Authorization is not required */ override fun helloWorld( params: TopLevelHelloWorldParams, - requestOptions: RequestOptions - ): String { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response.use { helloWorldHandler.handle(it) } + requestOptions: RequestOptions, + ): String = + // get /v1 + withRawResponse().helloWorld(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + TopLevelService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): TopLevelService.WithRawResponse = + TopLevelServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier).build() + ) + + private val helloWorldHandler: Handler = stringHandler() + + override fun helloWorld( + params: TopLevelHelloWorldParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1") + .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 { helloWorldHandler.handle(it) } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserService.kt index 70e079b2..c097ef66 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserService.kt @@ -1,29 +1,107 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.User import com.braintrustdata.api.models.UserListPage import com.braintrustdata.api.models.UserListParams import com.braintrustdata.api.models.UserRetrieveParams +import com.google.errorprone.annotations.MustBeClosed interface UserService { + /** + * 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: (ClientOptions.Builder) -> Unit): UserService + /** Get a user object by its id */ + fun retrieve( + userId: String, + params: UserRetrieveParams = UserRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): User = retrieve(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see retrieve */ fun retrieve( params: UserRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): User + /** @see retrieve */ + fun retrieve(userId: String, requestOptions: RequestOptions): User = + retrieve(userId, UserRetrieveParams.none(), requestOptions) + /** * List out all users. The users are sorted by creation date, with the most recently-created * users coming first */ fun list( - params: UserListParams, - requestOptions: RequestOptions = RequestOptions.none() + params: UserListParams = UserListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): UserListPage + + /** @see list */ + fun list(requestOptions: RequestOptions): UserListPage = + list(UserListParams.none(), requestOptions) + + /** A view of [UserService] 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: (ClientOptions.Builder) -> Unit): UserService.WithRawResponse + + /** + * Returns a raw HTTP response for `get /v1/user/{user_id}`, but is otherwise the same as + * [UserService.retrieve]. + */ + @MustBeClosed + fun retrieve( + userId: String, + params: UserRetrieveParams = UserRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: UserRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve(userId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(userId, UserRetrieveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/user`, but is otherwise the same as + * [UserService.list]. + */ + @MustBeClosed + fun list( + params: UserListParams = UserListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see list */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(UserListParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserServiceImpl.kt index 28ff5d7a..d12d91c6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/UserServiceImpl.kt @@ -4,76 +4,114 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.User import com.braintrustdata.api.models.UserListPage +import com.braintrustdata.api.models.UserListPageResponse import com.braintrustdata.api.models.UserListParams import com.braintrustdata.api.models.UserRetrieveParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class UserServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : UserService { +class UserServiceImpl internal constructor(private val clientOptions: ClientOptions) : UserService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: UserService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): UserService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): UserService = + UserServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun retrieve(params: UserRetrieveParams, requestOptions: RequestOptions): User = + // get /v1/user/{user_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun list(params: UserListParams, requestOptions: RequestOptions): UserListPage = + // get /v1/user + withRawResponse().list(params, requestOptions).parse() - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + UserService.WithRawResponse { - /** Get a user object by its id */ - override fun retrieve(params: UserRetrieveParams, requestOptions: RequestOptions): User { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "user", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): UserService.WithRawResponse = + UserServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: UserRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "user", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * List out all users. The users are sorted by creation date, with the most recently-created - * users coming first - */ - override fun list(params: UserListParams, requestOptions: RequestOptions): UserListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "user") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun list( + params: UserListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "user") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + UserListPage.builder() + .service(UserServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { UserListPage.of(this, params, it) } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewService.kt index 4f19295d..8fafef8e 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.View import com.braintrustdata.api.models.ViewCreateParams import com.braintrustdata.api.models.ViewDeleteParams @@ -13,22 +13,42 @@ import com.braintrustdata.api.models.ViewListParams import com.braintrustdata.api.models.ViewReplaceParams import com.braintrustdata.api.models.ViewRetrieveParams import com.braintrustdata.api.models.ViewUpdateParams +import com.google.errorprone.annotations.MustBeClosed interface ViewService { + /** + * 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: (ClientOptions.Builder) -> Unit): ViewService + /** * Create a new view. If there is an existing view with the same name as the one specified in * the request, will return the existing view unmodified */ fun create( params: ViewCreateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): View /** Get a view object by its id */ fun retrieve( + viewId: String, params: ViewRetrieveParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): View = retrieve(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see retrieve */ + fun retrieve( + params: ViewRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), ): View /** @@ -37,8 +57,15 @@ interface ViewService { * or setting them to null. */ fun update( + viewId: String, params: ViewUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): View = update(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see update */ + fun update( + params: ViewUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), ): View /** @@ -47,13 +74,20 @@ interface ViewService { */ fun list( params: ViewListParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): ViewListPage /** Delete a view object by its id */ fun delete( + viewId: String, params: ViewDeleteParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), + ): View = delete(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see delete */ + fun delete( + params: ViewDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), ): View /** @@ -62,6 +96,102 @@ interface ViewService { */ fun replace( params: ViewReplaceParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): View + + /** A view of [ViewService] 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: (ClientOptions.Builder) -> Unit): ViewService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/view`, but is otherwise the same as + * [ViewService.create]. + */ + @MustBeClosed + fun create( + params: ViewCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/view/{view_id}`, but is otherwise the same as + * [ViewService.retrieve]. + */ + @MustBeClosed + fun retrieve( + viewId: String, + params: ViewRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: ViewRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `patch /v1/view/{view_id}`, but is otherwise the same as + * [ViewService.update]. + */ + @MustBeClosed + fun update( + viewId: String, + params: ViewUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = update(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see update */ + @MustBeClosed + fun update( + params: ViewUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/view`, but is otherwise the same as + * [ViewService.list]. + */ + @MustBeClosed + fun list( + params: ViewListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `delete /v1/view/{view_id}`, but is otherwise the same as + * [ViewService.delete]. + */ + @MustBeClosed + fun delete( + viewId: String, + params: ViewDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = delete(params.toBuilder().viewId(viewId).build(), requestOptions) + + /** @see delete */ + @MustBeClosed + fun delete( + params: ViewDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `put /v1/view`, but is otherwise the same as + * [ViewService.replace]. + */ + @MustBeClosed + fun replace( + params: ViewReplaceParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewServiceImpl.kt index f682e6d6..6d5aa2a6 100755 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/ViewServiceImpl.kt @@ -4,195 +4,249 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.View import com.braintrustdata.api.models.ViewCreateParams import com.braintrustdata.api.models.ViewDeleteParams import com.braintrustdata.api.models.ViewListPage +import com.braintrustdata.api.models.ViewListPageResponse import com.braintrustdata.api.models.ViewListParams import com.braintrustdata.api.models.ViewReplaceParams import com.braintrustdata.api.models.ViewRetrieveParams import com.braintrustdata.api.models.ViewUpdateParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler - -class ViewServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : ViewService { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val createHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create a new view. If there is an existing view with the same name as the one specified in - * the request, will return the existing view unmodified - */ - override fun create(params: ViewCreateParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "view") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { createHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + +class ViewServiceImpl internal constructor(private val clientOptions: ClientOptions) : ViewService { + + private val withRawResponse: ViewService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ViewService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): ViewService = + ViewServiceImpl(clientOptions.toBuilder().apply(modifier).build()) + + override fun create(params: ViewCreateParams, requestOptions: RequestOptions): View = + // post /v1/view + withRawResponse().create(params, requestOptions).parse() + + override fun retrieve(params: ViewRetrieveParams, requestOptions: RequestOptions): View = + // get /v1/view/{view_id} + withRawResponse().retrieve(params, requestOptions).parse() + + override fun update(params: ViewUpdateParams, requestOptions: RequestOptions): View = + // patch /v1/view/{view_id} + withRawResponse().update(params, requestOptions).parse() + + override fun list(params: ViewListParams, requestOptions: RequestOptions): ViewListPage = + // get /v1/view + withRawResponse().list(params, requestOptions).parse() + + override fun delete(params: ViewDeleteParams, requestOptions: RequestOptions): View = + // delete /v1/view/{view_id} + withRawResponse().delete(params, requestOptions).parse() + + override fun replace(params: ViewReplaceParams, requestOptions: RequestOptions): View = + // put /v1/view + withRawResponse().replace(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ViewService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): ViewService.WithRawResponse = + ViewServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val createHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ViewCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view") + .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 { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val retrieveHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Get a view object by its id */ - override fun retrieve(params: ViewRetrieveParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "view", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { retrieveHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val retrieveHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: ViewRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("viewId", params.viewId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view", params._pathParam(0)) + .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 { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Partially update a view object. Specify the fields to update in the payload. Any object-type - * fields will be deep-merged with existing content. Currently we do not support removing fields - * or setting them to null. - */ - override fun update(params: ViewUpdateParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "view", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val updateHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: ViewUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("viewId", params.viewId()) + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view", params._pathParam(0)) + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * List out all views. The views are sorted by creation date, with the most recently-created - * views coming first - */ - override fun list(params: ViewListParams, requestOptions: RequestOptions): ViewListPage { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "view") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { listHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun list( + params: ViewListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view") + .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 { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + ViewListPage.builder() + .service(ViewServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() } - } - .let { ViewListPage.of(this, params, it) } + } } - } - private val deleteHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** Delete a view object by its id */ - override fun delete(params: ViewDeleteParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.DELETE) - .addPathSegments("v1", "view", params.getPathParam(0)) - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { deleteHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val deleteHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun delete( + params: ViewDeleteParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("viewId", params.viewId()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view", params._pathParam(0)) + .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 { deleteHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val replaceHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) - - /** - * Create or replace view. If there is an existing view with the same name as the one specified - * in the request, will replace the existing view with the provided fields - */ - override fun replace(params: ViewReplaceParams, requestOptions: RequestOptions): View { - val request = - HttpRequest.builder() - .method(HttpMethod.PUT) - .addPathSegments("v1", "view") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { replaceHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + private val replaceHandler: Handler = jsonHandler(clientOptions.jsonMapper) + + override fun replace( + params: ViewReplaceParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "view") + .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 { replaceHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberService.kt index 5e2b2a4f..fd58a5e8 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberService.kt @@ -1,18 +1,63 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking.organizations +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.OrganizationMemberUpdateParams import com.braintrustdata.api.models.PatchOrganizationMembersOutput +import com.google.errorprone.annotations.MustBeClosed interface MemberService { + /** + * 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: (ClientOptions.Builder) -> Unit): MemberService + /** Modify organization membership */ fun update( - params: OrganizationMemberUpdateParams, - requestOptions: RequestOptions = RequestOptions.none() + params: OrganizationMemberUpdateParams = OrganizationMemberUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): PatchOrganizationMembersOutput + + /** @see update */ + fun update(requestOptions: RequestOptions): PatchOrganizationMembersOutput = + update(OrganizationMemberUpdateParams.none(), requestOptions) + + /** A view of [MemberService] 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: (ClientOptions.Builder) -> Unit): MemberService.WithRawResponse + + /** + * Returns a raw HTTP response for `patch /v1/organization/members`, but is otherwise the + * same as [MemberService.update]. + */ + @MustBeClosed + fun update( + params: OrganizationMemberUpdateParams = OrganizationMemberUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see update */ + @MustBeClosed + fun update( + requestOptions: RequestOptions + ): HttpResponseFor = + update(OrganizationMemberUpdateParams.none(), requestOptions) + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceImpl.kt index 749d7bf8..4eb1c38c 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceImpl.kt @@ -4,51 +4,76 @@ package com.braintrustdata.api.services.blocking.organizations import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.OrganizationMemberUpdateParams import com.braintrustdata.api.models.PatchOrganizationMembersOutput -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class MemberServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : MemberService { +class MemberServiceImpl internal constructor(private val clientOptions: ClientOptions) : + MemberService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: MemberService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): MemberService.WithRawResponse = withRawResponse - private val updateHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): MemberService = + MemberServiceImpl(clientOptions.toBuilder().apply(modifier).build()) - /** Modify organization membership */ override fun update( params: OrganizationMemberUpdateParams, - requestOptions: RequestOptions - ): PatchOrganizationMembersOutput { - val request = - HttpRequest.builder() - .method(HttpMethod.PATCH) - .addPathSegments("v1", "organization", "members") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { updateHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): PatchOrganizationMembersOutput = + // patch /v1/organization/members + withRawResponse().update(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + MemberService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): MemberService.WithRawResponse = + MemberServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val updateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun update( + params: OrganizationMemberUpdateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.PATCH) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "organization", "members") + .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 { updateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogService.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogService.kt index 3a21d541..c6d95328 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogService.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogService.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.braintrustdata.api.services.blocking.projects +import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.http.HttpResponseFor import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchProjectLogsEventsResponse import com.braintrustdata.api.models.InsertEventsResponse @@ -12,36 +12,197 @@ import com.braintrustdata.api.models.ProjectLogFeedbackParams import com.braintrustdata.api.models.ProjectLogFetchParams import com.braintrustdata.api.models.ProjectLogFetchPostParams import com.braintrustdata.api.models.ProjectLogInsertParams +import com.google.errorprone.annotations.MustBeClosed interface LogService { + /** + * 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: (ClientOptions.Builder) -> Unit): LogService + /** Log feedback for a set of project logs events */ + fun feedback( + projectId: String, + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FeedbackResponseSchema = + feedback(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see feedback */ fun feedback( params: ProjectLogFeedbackParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FeedbackResponseSchema /** * Fetch the events in a project logs. Equivalent to the POST form of the same path, but with - * the parameters in the URL query rather than in the request body + * the parameters in the URL query rather than in the request body. For more complex queries, + * use the `POST /btql` endpoint. */ + fun fetch( + projectId: String, + params: ProjectLogFetchParams = ProjectLogFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchProjectLogsEventsResponse = + fetch(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetch */ fun fetch( params: ProjectLogFetchParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchProjectLogsEventsResponse + /** @see fetch */ + fun fetch(projectId: String, requestOptions: RequestOptions): FetchProjectLogsEventsResponse = + fetch(projectId, ProjectLogFetchParams.none(), requestOptions) + /** * Fetch the events in a project logs. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query + * parameters in the request body rather than in the URL query. For more complex queries, use + * the `POST /btql` endpoint. */ + fun fetchPost( + projectId: String, + params: ProjectLogFetchPostParams = ProjectLogFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FetchProjectLogsEventsResponse = + fetchPost(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetchPost */ fun fetchPost( params: ProjectLogFetchPostParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): FetchProjectLogsEventsResponse + /** @see fetchPost */ + fun fetchPost( + projectId: String, + requestOptions: RequestOptions, + ): FetchProjectLogsEventsResponse = + fetchPost(projectId, ProjectLogFetchPostParams.none(), requestOptions) + /** Insert a set of events into the project logs */ + fun insert( + projectId: String, + params: ProjectLogInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): InsertEventsResponse = + insert(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see insert */ fun insert( params: ProjectLogInsertParams, - requestOptions: RequestOptions = RequestOptions.none() + requestOptions: RequestOptions = RequestOptions.none(), ): InsertEventsResponse + + /** A view of [LogService] 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: (ClientOptions.Builder) -> Unit): LogService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /v1/project_logs/{project_id}/feedback`, but is + * otherwise the same as [LogService.feedback]. + */ + @MustBeClosed + fun feedback( + projectId: String, + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + feedback(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see feedback */ + @MustBeClosed + fun feedback( + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `get /v1/project_logs/{project_id}/fetch`, but is + * otherwise the same as [LogService.fetch]. + */ + @MustBeClosed + fun fetch( + projectId: String, + params: ProjectLogFetchParams = ProjectLogFetchParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetch(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetch */ + @MustBeClosed + fun fetch( + params: ProjectLogFetchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetch */ + @MustBeClosed + fun fetch( + projectId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetch(projectId, ProjectLogFetchParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/project_logs/{project_id}/fetch`, but is + * otherwise the same as [LogService.fetchPost]. + */ + @MustBeClosed + fun fetchPost( + projectId: String, + params: ProjectLogFetchPostParams = ProjectLogFetchPostParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + fetchPost(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see fetchPost */ + @MustBeClosed + fun fetchPost( + params: ProjectLogFetchPostParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see fetchPost */ + @MustBeClosed + fun fetchPost( + projectId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + fetchPost(projectId, ProjectLogFetchPostParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/project_logs/{project_id}/insert`, but is + * otherwise the same as [LogService.insert]. + */ + @MustBeClosed + fun insert( + projectId: String, + params: ProjectLogInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + insert(params.toBuilder().projectId(projectId).build(), requestOptions) + + /** @see insert */ + @MustBeClosed + fun insert( + params: ProjectLogInsertParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } } diff --git a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceImpl.kt b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceImpl.kt index 9f21671a..12f8e2f9 100644 --- a/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceImpl.kt +++ b/braintrust-kotlin-core/src/main/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceImpl.kt @@ -4,10 +4,18 @@ package com.braintrustdata.api.services.blocking.projects import com.braintrustdata.api.core.ClientOptions import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.checkRequired +import com.braintrustdata.api.core.handlers.errorBodyHandler +import com.braintrustdata.api.core.handlers.errorHandler +import com.braintrustdata.api.core.handlers.jsonHandler import com.braintrustdata.api.core.http.HttpMethod import com.braintrustdata.api.core.http.HttpRequest +import com.braintrustdata.api.core.http.HttpResponse import com.braintrustdata.api.core.http.HttpResponse.Handler -import com.braintrustdata.api.errors.BraintrustError +import com.braintrustdata.api.core.http.HttpResponseFor +import com.braintrustdata.api.core.http.json +import com.braintrustdata.api.core.http.parseable +import com.braintrustdata.api.core.prepare import com.braintrustdata.api.models.FeedbackResponseSchema import com.braintrustdata.api.models.FetchProjectLogsEventsResponse import com.braintrustdata.api.models.InsertEventsResponse @@ -15,138 +23,178 @@ import com.braintrustdata.api.models.ProjectLogFeedbackParams import com.braintrustdata.api.models.ProjectLogFetchParams import com.braintrustdata.api.models.ProjectLogFetchPostParams import com.braintrustdata.api.models.ProjectLogInsertParams -import com.braintrustdata.api.services.errorHandler -import com.braintrustdata.api.services.json -import com.braintrustdata.api.services.jsonHandler -import com.braintrustdata.api.services.withErrorHandler -class LogServiceImpl -constructor( - private val clientOptions: ClientOptions, -) : LogService { +class LogServiceImpl internal constructor(private val clientOptions: ClientOptions) : LogService { - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + private val withRawResponse: LogService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): LogService.WithRawResponse = withRawResponse - private val feedbackHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun withOptions(modifier: (ClientOptions.Builder) -> Unit): LogService = + LogServiceImpl(clientOptions.toBuilder().apply(modifier).build()) - /** Log feedback for a set of project logs events */ override fun feedback( params: ProjectLogFeedbackParams, - requestOptions: RequestOptions - ): FeedbackResponseSchema { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "feedback") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { feedbackHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + requestOptions: RequestOptions, + ): FeedbackResponseSchema = + // post /v1/project_logs/{project_id}/feedback + withRawResponse().feedback(params, requestOptions).parse() + + override fun fetch( + params: ProjectLogFetchParams, + requestOptions: RequestOptions, + ): FetchProjectLogsEventsResponse = + // get /v1/project_logs/{project_id}/fetch + withRawResponse().fetch(params, requestOptions).parse() + + override fun fetchPost( + params: ProjectLogFetchPostParams, + requestOptions: RequestOptions, + ): FetchProjectLogsEventsResponse = + // post /v1/project_logs/{project_id}/fetch + withRawResponse().fetchPost(params, requestOptions).parse() + + override fun insert( + params: ProjectLogInsertParams, + requestOptions: RequestOptions, + ): InsertEventsResponse = + // post /v1/project_logs/{project_id}/insert + withRawResponse().insert(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + LogService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: (ClientOptions.Builder) -> Unit + ): LogService.WithRawResponse = + LogServiceImpl.WithRawResponseImpl(clientOptions.toBuilder().apply(modifier).build()) + + private val feedbackHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun feedback( + params: ProjectLogFeedbackParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "feedback") + .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 { feedbackHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a project logs. Equivalent to the POST form of the same path, but with - * the parameters in the URL query rather than in the request body - */ - override fun fetch( - params: ProjectLogFetchParams, - requestOptions: RequestOptions - ): FetchProjectLogsEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { fetchHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun fetch( + params: ProjectLogFetchParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "fetch") + .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 { fetchHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val fetchPostHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) + private val fetchPostHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** - * Fetch the events in a project logs. Equivalent to the GET form of the same path, but with the - * parameters in the request body rather than in the URL query - */ - override fun fetchPost( - params: ProjectLogFetchPostParams, - requestOptions: RequestOptions - ): FetchProjectLogsEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "fetch") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { fetchPostHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun fetchPost( + params: ProjectLogFetchPostParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "fetch") + .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 { fetchPostHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } - } - private val insertHandler: Handler = - jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val insertHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - /** Insert a set of events into the project logs */ - override fun insert( - params: ProjectLogInsertParams, - requestOptions: RequestOptions - ): InsertEventsResponse { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegments("v1", "project_logs", params.getPathParam(0), "insert") - .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) - .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) - .body(json(clientOptions.jsonMapper, params.getBody())) - .build() - return clientOptions.httpClient.execute(request, requestOptions).let { response -> - response - .use { insertHandler.handle(it) } - .apply { - if (requestOptions.responseValidation ?: clientOptions.responseValidation) { - validate() + override fun insert( + params: ProjectLogInsertParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("projectId", params.projectId()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "project_logs", params._pathParam(0), "insert") + .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 { insertHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } } - } + } } } } diff --git a/braintrust-kotlin-core/src/main/resources/META-INF/proguard/braintrust-kotlin-core.pro b/braintrust-kotlin-core/src/main/resources/META-INF/proguard/braintrust-kotlin-core.pro new file mode 100644 index 00000000..02cd18c2 --- /dev/null +++ b/braintrust-kotlin-core/src/main/resources/META-INF/proguard/braintrust-kotlin-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.braintrustdata.api.** { *; } +-keep @com.fasterxml.jackson.databind.annotation.JsonDeserialize class com.braintrustdata.api.** { *; } + +# Jackson uses reflection to serialize and deserialize our classes based on their constructors and annotated members. +-keepclassmembers class com.braintrustdata.api.** { + (...); + @com.fasterxml.jackson.annotation.* *; +} \ No newline at end of file diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/TestServerExtension.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/TestServerExtension.kt index d79a0c57..1d2dd2d0 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/TestServerExtension.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/TestServerExtension.kt @@ -36,7 +36,7 @@ class TestServerExtension : BeforeAllCallback, ExecutionCondition { $ prism mock path/to/your.openapi.yml """ .trimIndent(), - e + e, ) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/AutoPagerAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/AutoPagerAsyncTest.kt new file mode 100644 index 00000000..abb93c32 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/AutoPagerAsyncTest.kt @@ -0,0 +1,37 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.runBlocking +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class AutoPagerAsyncTest { + + private class PageAsyncImpl( + private val items: List, + private val nextPage: PageAsync? = null, + ) : PageAsync { + + override fun hasNextPage(): Boolean = nextPage != null + + override suspend fun nextPage(): PageAsync = nextPage!! + + override fun items(): List = items + } + + @Test + fun collect() { + val firstPage = + PageAsyncImpl( + listOf("chunk1", "chunk2"), + nextPage = PageAsyncImpl(listOf("chunk3", "chunk4")), + ) + + val autoPager = AutoPagerAsync.from(firstPage) + + assertThat(runBlocking { autoPager.toList() }) + .containsExactly("chunk1", "chunk2", "chunk3", "chunk4") + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/AutoPagerTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/AutoPagerTest.kt new file mode 100644 index 00000000..826b6432 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/AutoPagerTest.kt @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class AutoPagerTest { + + private class PageImpl( + private val items: List, + private val nextPage: Page? = null, + ) : Page { + + override fun hasNextPage(): Boolean = nextPage != null + + override fun nextPage(): Page = nextPage!! + + override fun items(): List = items + } + + @Test + fun iterator() { + val firstPage = + PageImpl(listOf("chunk1", "chunk2"), nextPage = PageImpl(listOf("chunk3", "chunk4"))) + + val autoPager = AutoPager.from(firstPage) + + assertThat(autoPager.asIterable()).containsExactly("chunk1", "chunk2", "chunk3", "chunk4") + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ClientOptionsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ClientOptionsTest.kt new file mode 100644 index 00000000..9e5eb475 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ClientOptionsTest.kt @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.core + +import com.braintrustdata.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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ObjectMappersTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ObjectMappersTest.kt new file mode 100644 index 00000000..b1a6e835 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ObjectMappersTest.kt @@ -0,0 +1,102 @@ +package com.braintrustdata.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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/PhantomReachableTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/PhantomReachableTest.kt new file mode 100644 index 00000000..787e3b1f --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/PhantomReachableTest.kt @@ -0,0 +1,27 @@ +package com.braintrustdata.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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/UtilsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/UtilsTest.kt new file mode 100644 index 00000000..43a97498 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/UtilsTest.kt @@ -0,0 +1,33 @@ +package com.braintrustdata.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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ValuesTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ValuesTest.kt new file mode 100644 index 00000000..f995f538 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/ValuesTest.kt @@ -0,0 +1,127 @@ +package com.braintrustdata.api.core + +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: Any? = null, + val expectedAsBoolean: Boolean? = null, + val expectedAsNumber: Number? = null, + val expectedAsString: String? = null, + val expectedAsArray: List? = null, + val expectedAsObject: Map? = null, + ) { + MISSING(JsonMissing.of(), expectedIsMissing = true), + NULL(JsonNull.of(), expectedIsNull = true), + KNOWN(KnownValue.of(NON_JSON), expectedAsKnown = NON_JSON), + KNOWN_BOOLEAN(KnownValue.of(true), expectedAsKnown = true, expectedAsBoolean = true), + BOOLEAN(JsonBoolean.of(true), expectedAsBoolean = true), + KNOWN_NUMBER(KnownValue.of(42), expectedAsKnown = 42, expectedAsNumber = 42), + NUMBER(JsonNumber.of(42), expectedAsNumber = 42), + KNOWN_STRING(KnownValue.of("hello"), expectedAsKnown = "hello", expectedAsString = "hello"), + STRING(JsonString.of("hello"), expectedAsString = "hello"), + KNOWN_ARRAY_NOT_ALL_JSON( + KnownValue.of(listOf("a", "b", NON_JSON)), + expectedAsKnown = listOf("a", "b", NON_JSON), + ), + KNOWN_ARRAY( + KnownValue.of(listOf("a", "b", "c")), + expectedAsKnown = listOf("a", "b", "c"), + expectedAsArray = listOf(JsonString.of("a"), JsonString.of("b"), JsonString.of("c")), + ), + ARRAY( + JsonArray.of(listOf(JsonString.of("a"), JsonString.of("b"), JsonString.of("c"))), + expectedAsArray = 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 = mapOf("a" to "b", 42 to "c"), + ), + KNOWN_OBJECT_NOT_ALL_JSON( + KnownValue.of(mapOf("a" to "b", "b" to NON_JSON)), + expectedAsKnown = mapOf("a" to "b", "b" to NON_JSON), + ), + KNOWN_OBJECT( + KnownValue.of(mapOf("a" to "b", "b" to "c")), + expectedAsKnown = mapOf("a" to "b", "b" to "c"), + expectedAsObject = 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 = 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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/HeadersTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/HeadersTest.kt new file mode 100644 index 00000000..a4e77e29 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/HeadersTest.kt @@ -0,0 +1,242 @@ +package com.braintrustdata.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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/HttpRequestTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/HttpRequestTest.kt deleted file mode 100755 index 8c937928..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/HttpRequestTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.braintrustdata.api.core.http - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class HttpRequestTest { - - @Test - fun caseInsensitiveHeadersAccessors() { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .putHeader("something_lowercase", "lowercase") - .putHeader("Something_Capitalized", "Capitalized") - .putHeader("SOMETHING_UPPERCASE", "UPPERCASE") - .build() - assertThat(request.headers.get("SOMETHING_LOWERCASE").getOrNull(0)).isEqualTo("lowercase") - assertThat(request.headers.get("something_capitalized").getOrNull(0)) - .isEqualTo("Capitalized") - assertThat(request.headers.get("Something_Uppercase").getOrNull(0)).isEqualTo("UPPERCASE") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/QueryParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/QueryParamsTest.kt new file mode 100644 index 00000000..0fd285c1 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/QueryParamsTest.kt @@ -0,0 +1,180 @@ +package com.braintrustdata.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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/RetryingHttpClientTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/RetryingHttpClientTest.kt index e610085a..f05136e1 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/RetryingHttpClientTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/RetryingHttpClientTest.kt @@ -1,66 +1,129 @@ package com.braintrustdata.api.core.http import com.braintrustdata.api.client.okhttp.OkHttpClient +import com.braintrustdata.api.core.RequestOptions +import com.braintrustdata.api.core.Sleeper +import com.braintrustdata.api.errors.BraintrustRetryableException 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 java.io.InputStream +import java.time.Duration import kotlinx.coroutines.runBlocking 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 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) { - httpClient = OkHttpClient.builder().baseUrl(wmRuntimeInfo.httpBaseUrl).build() + 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 suspend fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse = trackClose(okHttpClient.executeAsync(request, requestOptions)) + + 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() } - @Test - fun byDefaultShouldNotAddIdempotencyHeaderToRequest() { - val request = - HttpRequest.builder().method(HttpMethod.POST).addPathSegment("something").build() + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute(async: Boolean) { stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) - val retryingClient = RetryingHttpClient.builder().httpClient(httpClient).build() - val response = retryingClient.execute(request) + 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() } - @Test - fun whenProvidedShouldAddIdempotencyHeaderToRequest() { - val request = - HttpRequest.builder().method(HttpMethod.POST).addPathSegment("something").build() + @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 = - RetryingHttpClient.builder() - .httpClient(httpClient) - .idempotencyHeader("X-Some-Header") - .build() - val response = retryingClient.execute(request) + 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 retryAfterHeader(async: Boolean) { - val request = - HttpRequest.builder().method(HttpMethod.POST).addPathSegment("something").build() + fun execute_withRetryAfterHeader(async: Boolean) { stubFor( post(urlPathEqualTo("/something")) - .inScenario("foo") // first we fail with a retry after header given as a date + // 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") @@ -69,52 +132,54 @@ internal class RetryingHttpClientTest { ) stubFor( post(urlPathEqualTo("/something")) - .inScenario("foo") // then we fail with a retry after header given as a delay + // 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")) - .inScenario("foo") // then we return a success + // Then we return a success + .inScenario("foo") .whenScenarioStateIs("RETRY_AFTER_DELAY") .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = - RetryingHttpClient.builder().httpClient(httpClient).maxRetries(2).build() + val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() val response = - if (async) runBlocking { retryingClient.executeAsync(request) } - else retryingClient.execute(request) + 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")) + .withHeader("x-stainless-retry-count", equalTo("0")), ) verify( 1, postRequestedFor(urlPathEqualTo("/something")) - .withHeader("x-stainless-retry-count", equalTo("1")) + .withHeader("x-stainless-retry-count", equalTo("1")), ) verify( 1, postRequestedFor(urlPathEqualTo("/something")) - .withHeader("x-stainless-retry-count", equalTo("2")) + .withHeader("x-stainless-retry-count", equalTo("2")), ) + assertNoResponseLeaks() } @ParameterizedTest @ValueSource(booleans = [false, true]) - fun overwriteRetryCountHeader(async: Boolean) { - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .addPathSegment("something") - .putHeader("x-stainless-retry-count", "42") - .build() + fun execute_withOverwrittenRetryCountHeader(async: Boolean) { stubFor( post(urlPathEqualTo("/something")) .inScenario("foo") // first we fail with a retry after header given as a date @@ -131,25 +196,31 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = - RetryingHttpClient.builder().httpClient(httpClient).maxRetries(2).build() + val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() val response = - if (async) runBlocking { retryingClient.executeAsync(request) } - else retryingClient.execute(request) + 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")) + .withHeader("x-stainless-retry-count", equalTo("42")), ) + assertNoResponseLeaks() } - @Test - fun retryAfterMsHeader() { - val request = - HttpRequest.builder().method(HttpMethod.POST).addPathSegment("something").build() + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryAfterMsHeader(async: Boolean) { stubFor( post(urlPathEqualTo("/something")) .inScenario("foo") @@ -164,10 +235,115 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = - RetryingHttpClient.builder().httpClient(httpClient).maxRetries(2).build() - val response = retryingClient.execute(request) + 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 BraintrustRetryableException("Simulated retryable failure") + } + return httpClient.execute(request, requestOptions) + } + + override suspend fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse { + callCount++ + if (callCount == 1) { + throw BraintrustRetryableException("Simulated retryable failure") + } + 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 suspend fun sleepAsync(duration: Duration) {} + + 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 suspend fun sleepAsync(duration: Duration) {} + + override fun close() {} + } + ) + + private fun HttpClient.execute(request: HttpRequest, async: Boolean): HttpResponse = + if (async) runBlocking { executeAsync(request) } 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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/SerializerTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/SerializerTest.kt deleted file mode 100755 index f1c1f965..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/core/http/SerializerTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.braintrustdata.api.core.http - -import com.braintrustdata.api.core.* -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import java.util.* -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SerializerTest { - @JsonDeserialize(builder = ClassWithBooleanFieldPrefixedWithIs.Builder::class) - @NoAutoDetect - class ClassWithBooleanFieldPrefixedWithIs - private constructor( - private val isActive: JsonField, - private val additionalProperties: Map, - ) { - private var validated: Boolean = false - - private var hashCode: Int = 0 - - fun isActive(): Boolean? = isActive.getNullable("is_active") - - @JsonProperty("is_active") @ExcludeMissing fun _isActive() = isActive - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun validate() = apply { - if (!validated) { - isActive() - validated = true - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ClassWithBooleanFieldPrefixedWithIs && - isActive == other.isActive && - additionalProperties == other.additionalProperties - } - - override fun hashCode(): Int { - if (hashCode == 0) { - hashCode = - Objects.hash( - isActive, - additionalProperties, - ) - } - return hashCode - } - - override fun toString() = - "MyClass{isActive=$isActive, additionalProperties=$additionalProperties}" - - companion object { - fun builder() = Builder() - } - - @NoAutoDetect - class Builder { - private var isActive: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - fun isActive(isActive: Boolean) = isActive(JsonField.of(isActive)) - - @JsonProperty("is_active") - @ExcludeMissing - fun isActive(isActive: JsonField) = apply { this.isActive = isActive } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - this.additionalProperties.putAll(additionalProperties) - } - - @JsonAnySetter - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - this.additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun build(): ClassWithBooleanFieldPrefixedWithIs = - ClassWithBooleanFieldPrefixedWithIs( - isActive, - additionalProperties.toUnmodifiable(), - ) - } - } - - @Test - fun serializeBooleanPrefixedWithIs() { - val value = ClassWithBooleanFieldPrefixedWithIs.builder().isActive(true).build() - assertThat(jsonMapper().writeValueAsString(value)).isEqualTo("{\"is_active\":true}") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AISecretTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AISecretTest.kt index 561dc76b..a8e2a6ee 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AISecretTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AISecretTest.kt @@ -2,31 +2,73 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AISecretTest { +internal class AISecretTest { @Test - fun createAISecret() { - val aISecret = + fun create() { + val aiSecret = AISecret.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .metadata(AISecret.Metadata.builder().build()) + .metadata( + AISecret.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .previewSecret("preview_secret") .type("type") + .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .build() - assertThat(aISecret).isNotNull - assertThat(aISecret.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(aISecret.name()).isEqualTo("name") - assertThat(aISecret.orgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(aISecret.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(aISecret.metadata()).isEqualTo(AISecret.Metadata.builder().build()) - assertThat(aISecret.previewSecret()).isEqualTo("preview_secret") - assertThat(aISecret.type()).isEqualTo("type") + + assertThat(aiSecret.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(aiSecret.name()).isEqualTo("name") + assertThat(aiSecret.orgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(aiSecret.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + assertThat(aiSecret.metadata()) + .isEqualTo( + AISecret.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + assertThat(aiSecret.previewSecret()).isEqualTo("preview_secret") + assertThat(aiSecret.type()).isEqualTo("type") + assertThat(aiSecret.updatedAt()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val aiSecret = + AISecret.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .metadata( + AISecret.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .previewSecret("preview_secret") + .type("type") + .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + + val roundtrippedAiSecret = + jsonMapper.readValue( + jsonMapper.writeValueAsString(aiSecret), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAiSecret).isEqualTo(aiSecret) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateParamsTest.kt index 7fe6d87f..cc746cc5 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateParamsTest.kt @@ -2,123 +2,99 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclBatchUpdateParamsTest { +internal class AclBatchUpdateParamsTest { @Test - fun createAclBatchUpdateParams() { + fun create() { AclBatchUpdateParams.builder() - .addAcls( - listOf( - AclBatchUpdateParams.AddAcl.builder() - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.AddAcl.ObjectType.ORGANIZATION) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.AddAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.AddAcl.RestrictObjectType.ORGANIZATION - ) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) + .addAddAcl( + AclBatchUpdateParams.AddAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - .removeAcls( - listOf( - AclBatchUpdateParams.RemoveAcl.builder() - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.RemoveAcl.ObjectType.ORGANIZATION) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.RemoveAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.RemoveAcl.RestrictObjectType.ORGANIZATION - ) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) + .addRemoveAcl( + AclBatchUpdateParams.RemoveAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) .build() } @Test - fun getBody() { + fun body() { val params = AclBatchUpdateParams.builder() - .addAcls( - listOf( - AclBatchUpdateParams.AddAcl.builder() - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.AddAcl.ObjectType.ORGANIZATION) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.AddAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.AddAcl.RestrictObjectType.ORGANIZATION - ) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - ) - .removeAcls( - listOf( - AclBatchUpdateParams.RemoveAcl.builder() - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.RemoveAcl.ObjectType.ORGANIZATION) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.RemoveAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.RemoveAcl.RestrictObjectType.ORGANIZATION - ) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - ) - .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.addAcls()) - .isEqualTo( - listOf( + .addAddAcl( AclBatchUpdateParams.AddAcl.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.AddAcl.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.AddAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.AddAcl.RestrictObjectType.ORGANIZATION - ) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) - ) - assertThat(body.removeAcls()) - .isEqualTo( - listOf( + .addRemoveAcl( AclBatchUpdateParams.RemoveAcl.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.RemoveAcl.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.RemoveAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.RemoveAcl.RestrictObjectType.ORGANIZATION - ) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) + .build() + + val body = params._body() + + assertThat(body.addAcls()) + .containsExactly( + AclBatchUpdateParams.AddAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + assertThat(body.removeAcls()) + .containsExactly( + AclBatchUpdateParams.RemoveAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = AclBatchUpdateParams.builder().build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponseTest.kt index a6d7aec5..e414f12a 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclBatchUpdateResponseTest.kt @@ -2,61 +2,59 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclBatchUpdateResponseTest { +internal class AclBatchUpdateResponseTest { @Test - fun createAclBatchUpdateResponse() { + fun create() { val aclBatchUpdateResponse = AclBatchUpdateResponse.builder() - .addedAcls( - listOf( - Acl.builder() - .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(Acl.ObjectType.ORGANIZATION) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(Acl.Permission.CREATE) - .restrictObjectType(Acl.RestrictObjectType.ORGANIZATION) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) + .addAddedAcl( + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - .removedAcls( - listOf( - Acl.builder() - .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(Acl.ObjectType.ORGANIZATION) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(Acl.Permission.CREATE) - .restrictObjectType(Acl.RestrictObjectType.ORGANIZATION) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) + .addRemovedAcl( + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) .build() - assertThat(aclBatchUpdateResponse).isNotNull + assertThat(aclBatchUpdateResponse.addedAcls()) .containsExactly( Acl.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(Acl.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(Acl.Permission.CREATE) - .restrictObjectType(Acl.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() @@ -67,14 +65,58 @@ class AclBatchUpdateResponseTest { .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(Acl.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(Acl.Permission.CREATE) - .restrictObjectType(Acl.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val aclBatchUpdateResponse = + AclBatchUpdateResponse.builder() + .addAddedAcl( + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .addRemovedAcl( + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedAclBatchUpdateResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(aclBatchUpdateResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAclBatchUpdateResponse).isEqualTo(aclBatchUpdateResponse) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclCreateParamsTest.kt index 95dcb724..2753f19a 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclCreateParamsTest.kt @@ -2,59 +2,59 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclCreateParamsTest { +internal class AclCreateParamsTest { @Test - fun createAclCreateParams() { + fun create() { AclCreateParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclCreateParams.Permission.CREATE) - .restrictObjectType(AclCreateParams.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getBody() { + fun body() { val params = AclCreateParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclCreateParams.Permission.CREATE) - .restrictObjectType(AclCreateParams.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(AclCreateParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(body.groupId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.permission()).isEqualTo(AclCreateParams.Permission.CREATE) - assertThat(body.restrictObjectType()) - .isEqualTo(AclCreateParams.RestrictObjectType.ORGANIZATION) + assertThat(body.permission()).isEqualTo(Permission.CREATE) + assertThat(body.restrictObjectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(body.roleId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = AclCreateParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(AclCreateParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclDeleteParamsTest.kt index 5b65f5d1..3f7c31e8 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclDeleteParamsTest.kt @@ -2,24 +2,22 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclDeleteParamsTest { +internal class AclDeleteParamsTest { @Test - fun createAclDeleteParams() { + fun create() { AclDeleteParams.builder().aclId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = AclDeleteParams.builder().aclId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "aclId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParamsTest.kt index 90f45c40..dbf30b1c 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclFindAndDeleteParamsTest.kt @@ -2,59 +2,59 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclFindAndDeleteParamsTest { +internal class AclFindAndDeleteParamsTest { @Test - fun createAclFindAndDeleteParams() { + fun create() { AclFindAndDeleteParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclFindAndDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclFindAndDeleteParams.Permission.CREATE) - .restrictObjectType(AclFindAndDeleteParams.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getBody() { + fun body() { val params = AclFindAndDeleteParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclFindAndDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclFindAndDeleteParams.Permission.CREATE) - .restrictObjectType(AclFindAndDeleteParams.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(AclFindAndDeleteParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(body.groupId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.permission()).isEqualTo(AclFindAndDeleteParams.Permission.CREATE) - assertThat(body.restrictObjectType()) - .isEqualTo(AclFindAndDeleteParams.RestrictObjectType.ORGANIZATION) + assertThat(body.permission()).isEqualTo(Permission.CREATE) + assertThat(body.restrictObjectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(body.roleId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = AclFindAndDeleteParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclFindAndDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(AclFindAndDeleteParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclListPageResponseTest.kt new file mode 100644 index 00000000..fdb2fe1a --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclListPageResponseTest.kt @@ -0,0 +1,79 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class AclListPageResponseTest { + + @Test + fun create() { + val aclListPageResponse = + AclListPageResponse.builder() + .addObject( + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(aclListPageResponse.objects()) + .containsExactly( + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val aclListPageResponse = + AclListPageResponse.builder() + .addObject( + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedAclListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(aclListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAclListPageResponse).isEqualTo(aclListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclListParamsTest.kt index cc02b4b4..e5288078 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclListParamsTest.kt @@ -2,58 +2,67 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclListParamsTest { +internal class AclListParamsTest { @Test - fun createAclListParams() { + fun create() { AclListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(AclListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = AclListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(AclListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("object_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("object_type", listOf(AclListParams.ObjectType.ORGANIZATION.toString())) - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf(AclListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("object_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("object_type", "organization") + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = AclListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - val expected = mutableMapOf>() - expected.put("object_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("object_type", listOf(AclListParams.ObjectType.ORGANIZATION.toString())) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("object_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("object_type", "organization") + .build() + ) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclRetrieveParamsTest.kt index ed334cc7..0dc6c6be 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclRetrieveParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclRetrieveParamsTest { +internal class AclRetrieveParamsTest { @Test - fun createAclRetrieveParams() { + fun create() { AclRetrieveParams.builder().aclId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = AclRetrieveParams.builder().aclId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "aclId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclTest.kt index 285b4fb8..c8b99c99 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AclTest.kt @@ -2,37 +2,62 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AclTest { +internal class AclTest { @Test - fun createAcl() { + fun create() { val acl = Acl.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(Acl.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(Acl.Permission.CREATE) - .restrictObjectType(Acl.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(acl).isNotNull + assertThat(acl.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(acl._objectOrgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(acl.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(acl.objectType()).isEqualTo(Acl.ObjectType.ORGANIZATION) + assertThat(acl.objectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(acl.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(acl.groupId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(acl.permission()).isEqualTo(Acl.Permission.CREATE) - assertThat(acl.restrictObjectType()).isEqualTo(Acl.RestrictObjectType.ORGANIZATION) + assertThat(acl.permission()).isEqualTo(Permission.CREATE) + assertThat(acl.restrictObjectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(acl.roleId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(acl.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val acl = + Acl.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._objectOrgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedAcl = + jsonMapper.readValue(jsonMapper.writeValueAsString(acl), jacksonTypeRef()) + + assertThat(roundtrippedAcl).isEqualTo(acl) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretCreateParamsTest.kt index 803786eb..1a0b68e5 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretCreateParamsTest.kt @@ -2,17 +2,21 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AiSecretCreateParamsTest { +internal class AiSecretCreateParamsTest { @Test - fun createAiSecretCreateParams() { + fun create() { AiSecretCreateParams.builder() .name("name") - .metadata(AiSecretCreateParams.Metadata.builder().build()) + .metadata( + AiSecretCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .orgName("org_name") .secret("secret") .type("type") @@ -20,29 +24,40 @@ class AiSecretCreateParamsTest { } @Test - fun getBody() { + fun body() { val params = AiSecretCreateParams.builder() .name("name") - .metadata(AiSecretCreateParams.Metadata.builder().build()) + .metadata( + AiSecretCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .orgName("org_name") .secret("secret") .type("type") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") - assertThat(body.metadata()).isEqualTo(AiSecretCreateParams.Metadata.builder().build()) + assertThat(body.metadata()) + .isEqualTo( + AiSecretCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(body.orgName()).isEqualTo("org_name") assertThat(body.secret()).isEqualTo("secret") assertThat(body.type()).isEqualTo("type") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = AiSecretCreateParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretDeleteParamsTest.kt index 5f984b71..0aecaacb 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretDeleteParamsTest.kt @@ -2,27 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AiSecretDeleteParamsTest { +internal class AiSecretDeleteParamsTest { @Test - fun createAiSecretDeleteParams() { + fun create() { AiSecretDeleteParams.builder().aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = AiSecretDeleteParams.builder() .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "aiSecretId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParamsTest.kt index e3e4da8a..91d646cd 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretFindAndDeleteParamsTest.kt @@ -2,31 +2,32 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AiSecretFindAndDeleteParamsTest { +internal class AiSecretFindAndDeleteParamsTest { @Test - fun createAiSecretFindAndDeleteParams() { + fun create() { AiSecretFindAndDeleteParams.builder().name("name").orgName("org_name").build() } @Test - fun getBody() { + fun body() { val params = AiSecretFindAndDeleteParams.builder().name("name").orgName("org_name").build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.orgName()).isEqualTo("org_name") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = AiSecretFindAndDeleteParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretListPageResponseTest.kt new file mode 100644 index 00000000..f37f7b6c --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretListPageResponseTest.kt @@ -0,0 +1,86 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class AiSecretListPageResponseTest { + + @Test + fun create() { + val aiSecretListPageResponse = + AiSecretListPageResponse.builder() + .addObject( + AISecret.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .metadata( + AISecret.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .previewSecret("preview_secret") + .type("type") + .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + ) + .build() + + assertThat(aiSecretListPageResponse.objects()) + .containsExactly( + AISecret.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .metadata( + AISecret.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .previewSecret("preview_secret") + .type("type") + .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val aiSecretListPageResponse = + AiSecretListPageResponse.builder() + .addObject( + AISecret.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .metadata( + AISecret.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .previewSecret("preview_secret") + .type("type") + .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + ) + .build() + + val roundtrippedAiSecretListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(aiSecretListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAiSecretListPageResponse).isEqualTo(aiSecretListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretListParamsTest.kt index 27820e93..20af378c 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretListParamsTest.kt @@ -2,60 +2,60 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AiSecretListParamsTest { +internal class AiSecretListParamsTest { @Test - fun createAiSecretListParams() { + fun create() { AiSecretListParams.builder() .aiSecretName("ai_secret_name") - .aiSecretType(AiSecretListParams.AiSecretType.ofString("string")) + .aiSecretType("string") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(AiSecretListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = AiSecretListParams.builder() .aiSecretName("ai_secret_name") - .aiSecretType(AiSecretListParams.AiSecretType.ofString("string")) + .aiSecretType("string") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(AiSecretListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ai_secret_name", listOf("ai_secret_name")) - expected.put( - "ai_secret_type", - listOf(AiSecretListParams.AiSecretType.ofString("string").toString()) - ) - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf( - AiSecretListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ai_secret_name", "ai_secret_name") + .put("ai_secret_type", "string") + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = AiSecretListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretReplaceParamsTest.kt index 3204ee97..06437b22 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretReplaceParamsTest.kt @@ -2,17 +2,21 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AiSecretReplaceParamsTest { +internal class AiSecretReplaceParamsTest { @Test - fun createAiSecretReplaceParams() { + fun create() { AiSecretReplaceParams.builder() .name("name") - .metadata(AiSecretReplaceParams.Metadata.builder().build()) + .metadata( + AiSecretReplaceParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .orgName("org_name") .secret("secret") .type("type") @@ -20,29 +24,40 @@ class AiSecretReplaceParamsTest { } @Test - fun getBody() { + fun body() { val params = AiSecretReplaceParams.builder() .name("name") - .metadata(AiSecretReplaceParams.Metadata.builder().build()) + .metadata( + AiSecretReplaceParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .orgName("org_name") .secret("secret") .type("type") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") - assertThat(body.metadata()).isEqualTo(AiSecretReplaceParams.Metadata.builder().build()) + assertThat(body.metadata()) + .isEqualTo( + AiSecretReplaceParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(body.orgName()).isEqualTo("org_name") assertThat(body.secret()).isEqualTo("secret") assertThat(body.type()).isEqualTo("type") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = AiSecretReplaceParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParamsTest.kt index c2a28575..6fa5c828 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretRetrieveParamsTest.kt @@ -2,27 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AiSecretRetrieveParamsTest { +internal class AiSecretRetrieveParamsTest { @Test - fun createAiSecretRetrieveParams() { + fun create() { AiSecretRetrieveParams.builder().aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = AiSecretRetrieveParams.builder() .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "aiSecretId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretUpdateParamsTest.kt index d324f0a2..fdd9399b 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/AiSecretUpdateParamsTest.kt @@ -2,17 +2,21 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class AiSecretUpdateParamsTest { +internal class AiSecretUpdateParamsTest { @Test - fun createAiSecretUpdateParams() { + fun create() { AiSecretUpdateParams.builder() .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .metadata(AiSecretUpdateParams.Metadata.builder().build()) + .metadata( + AiSecretUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .secret("secret") .type("type") @@ -20,43 +24,52 @@ class AiSecretUpdateParamsTest { } @Test - fun getBody() { + fun pathParams() { val params = AiSecretUpdateParams.builder() .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .metadata(AiSecretUpdateParams.Metadata.builder().build()) - .name("name") - .secret("secret") - .type("type") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.metadata()).isEqualTo(AiSecretUpdateParams.Metadata.builder().build()) - assertThat(body.name()).isEqualTo("name") - assertThat(body.secret()).isEqualTo("secret") - assertThat(body.type()).isEqualTo("type") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = AiSecretUpdateParams.builder() .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .metadata( + AiSecretUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .secret("secret") + .type("type") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + + assertThat(body.metadata()) + .isEqualTo( + AiSecretUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + assertThat(body.name()).isEqualTo("name") + assertThat(body.secret()).isEqualTo("secret") + assertThat(body.type()).isEqualTo("type") } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = AiSecretUpdateParams.builder() .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "aiSecretId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyCreateParamsTest.kt index 8c337a43..de83e00b 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyCreateParamsTest.kt @@ -2,31 +2,32 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ApiKeyCreateParamsTest { +internal class ApiKeyCreateParamsTest { @Test - fun createApiKeyCreateParams() { + fun create() { ApiKeyCreateParams.builder().name("name").orgName("org_name").build() } @Test - fun getBody() { + fun body() { val params = ApiKeyCreateParams.builder().name("name").orgName("org_name").build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.orgName()).isEqualTo("org_name") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ApiKeyCreateParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParamsTest.kt index bbcd063d..4172b7c4 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyDeleteParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ApiKeyDeleteParamsTest { +internal class ApiKeyDeleteParamsTest { @Test - fun createApiKeyDeleteParams() { + fun create() { ApiKeyDeleteParams.builder().apiKeyId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = ApiKeyDeleteParams.builder().apiKeyId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "apiKeyId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyListPageResponseTest.kt new file mode 100644 index 00000000..396312d3 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyListPageResponseTest.kt @@ -0,0 +1,67 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ApiKeyListPageResponseTest { + + @Test + fun create() { + val apiKeyListPageResponse = + ApiKeyListPageResponse.builder() + .addObject( + ApiKey.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .previewName("preview_name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(apiKeyListPageResponse.objects()) + .containsExactly( + ApiKey.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .previewName("preview_name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val apiKeyListPageResponse = + ApiKeyListPageResponse.builder() + .addObject( + ApiKey.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .previewName("preview_name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedApiKeyListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(apiKeyListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedApiKeyListPageResponse).isEqualTo(apiKeyListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyListParamsTest.kt index e749c8e0..e9582d7c 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyListParamsTest.kt @@ -2,52 +2,57 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ApiKeyListParamsTest { +internal class ApiKeyListParamsTest { @Test - fun createApiKeyListParams() { + fun create() { ApiKeyListParams.builder() .apiKeyName("api_key_name") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ApiKeyListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = ApiKeyListParams.builder() .apiKeyName("api_key_name") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ApiKeyListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("api_key_name", listOf("api_key_name")) - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf(ApiKeyListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("api_key_name", "api_key_name") + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = ApiKeyListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParamsTest.kt index 48a5016b..1612ee3b 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyRetrieveParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ApiKeyRetrieveParamsTest { +internal class ApiKeyRetrieveParamsTest { @Test - fun createApiKeyRetrieveParams() { + fun create() { ApiKeyRetrieveParams.builder().apiKeyId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = ApiKeyRetrieveParams.builder().apiKeyId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "apiKeyId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyTest.kt index 52a3e5d0..47ddcf54 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ApiKeyTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ApiKeyTest { +internal class ApiKeyTest { @Test - fun createApiKey() { + fun create() { val apiKey = ApiKey.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -19,7 +21,7 @@ class ApiKeyTest { .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(apiKey).isNotNull + assertThat(apiKey.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(apiKey.name()).isEqualTo("name") assertThat(apiKey.previewName()).isEqualTo("preview_name") @@ -27,4 +29,23 @@ class ApiKeyTest { assertThat(apiKey.orgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(apiKey.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val apiKey = + ApiKey.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .previewName("preview_name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedApiKey = + jsonMapper.readValue(jsonMapper.writeValueAsString(apiKey), jacksonTypeRef()) + + assertThat(roundtrippedApiKey).isEqualTo(apiKey) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImageTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImageTest.kt index fbf9f7e4..ccce4723 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImageTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartImageTest.kt @@ -2,13 +2,15 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ChatCompletionContentPartImageTest { +internal class ChatCompletionContentPartImageTest { @Test - fun createChatCompletionContentPartImage() { + fun create() { val chatCompletionContentPartImage = ChatCompletionContentPartImage.builder() .imageUrl( @@ -19,7 +21,7 @@ class ChatCompletionContentPartImageTest { ) .type(ChatCompletionContentPartImage.Type.IMAGE_URL) .build() - assertThat(chatCompletionContentPartImage).isNotNull + assertThat(chatCompletionContentPartImage.imageUrl()) .isEqualTo( ChatCompletionContentPartImage.ImageUrl.builder() @@ -30,4 +32,28 @@ class ChatCompletionContentPartImageTest { assertThat(chatCompletionContentPartImage.type()) .isEqualTo(ChatCompletionContentPartImage.Type.IMAGE_URL) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val chatCompletionContentPartImage = + ChatCompletionContentPartImage.builder() + .imageUrl( + ChatCompletionContentPartImage.ImageUrl.builder() + .url("url") + .detail(ChatCompletionContentPartImage.ImageUrl.Detail.AUTO) + .build() + ) + .type(ChatCompletionContentPartImage.Type.IMAGE_URL) + .build() + + val roundtrippedChatCompletionContentPartImage = + jsonMapper.readValue( + jsonMapper.writeValueAsString(chatCompletionContentPartImage), + jacksonTypeRef(), + ) + + assertThat(roundtrippedChatCompletionContentPartImage) + .isEqualTo(chatCompletionContentPartImage) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartTextTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartTextTest.kt index ec26433e..321b2b74 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartTextTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionContentPartTextTest.kt @@ -2,21 +2,42 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ChatCompletionContentPartTextTest { +internal class ChatCompletionContentPartTextTest { @Test - fun createChatCompletionContentPartText() { + fun create() { val chatCompletionContentPartText = ChatCompletionContentPartText.builder() .type(ChatCompletionContentPartText.Type.TEXT) .text("text") .build() - assertThat(chatCompletionContentPartText).isNotNull + assertThat(chatCompletionContentPartText.type()) .isEqualTo(ChatCompletionContentPartText.Type.TEXT) assertThat(chatCompletionContentPartText.text()).isEqualTo("text") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val chatCompletionContentPartText = + ChatCompletionContentPartText.builder() + .type(ChatCompletionContentPartText.Type.TEXT) + .text("text") + .build() + + val roundtrippedChatCompletionContentPartText = + jsonMapper.readValue( + jsonMapper.writeValueAsString(chatCompletionContentPartText), + jacksonTypeRef(), + ) + + assertThat(roundtrippedChatCompletionContentPartText) + .isEqualTo(chatCompletionContentPartText) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCallTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCallTest.kt index c609ef38..4ff757fd 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCallTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ChatCompletionMessageToolCallTest.kt @@ -2,13 +2,15 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ChatCompletionMessageToolCallTest { +internal class ChatCompletionMessageToolCallTest { @Test - fun createChatCompletionMessageToolCall() { + fun create() { val chatCompletionMessageToolCall = ChatCompletionMessageToolCall.builder() .id("id") @@ -20,7 +22,7 @@ class ChatCompletionMessageToolCallTest { ) .type(ChatCompletionMessageToolCall.Type.FUNCTION) .build() - assertThat(chatCompletionMessageToolCall).isNotNull + assertThat(chatCompletionMessageToolCall.id()).isEqualTo("id") assertThat(chatCompletionMessageToolCall.function()) .isEqualTo( @@ -32,4 +34,29 @@ class ChatCompletionMessageToolCallTest { assertThat(chatCompletionMessageToolCall.type()) .isEqualTo(ChatCompletionMessageToolCall.Type.FUNCTION) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val chatCompletionMessageToolCall = + ChatCompletionMessageToolCall.builder() + .id("id") + .function( + ChatCompletionMessageToolCall.Function.builder() + .arguments("arguments") + .name("name") + .build() + ) + .type(ChatCompletionMessageToolCall.Type.FUNCTION) + .build() + + val roundtrippedChatCompletionMessageToolCall = + jsonMapper.readValue( + jsonMapper.writeValueAsString(chatCompletionMessageToolCall), + jacksonTypeRef(), + ) + + assertThat(roundtrippedChatCompletionMessageToolCall) + .isEqualTo(chatCompletionMessageToolCall) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CodeBundleTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CodeBundleTest.kt index 801e520b..356b4e9c 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CodeBundleTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CodeBundleTest.kt @@ -2,28 +2,28 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class CodeBundleTest { +internal class CodeBundleTest { @Test - fun createCodeBundle() { + fun create() { val codeBundle = CodeBundle.builder() .bundleId("bundle_id") .location( - CodeBundle.Location.ofExperiment( - CodeBundle.Location.Experiment.builder() - .evalName("eval_name") - .position( - CodeBundle.Location.Experiment.Position.ofTask( - Task.builder().type(Task.Type.TASK).build() - ) - ) - .type(CodeBundle.Location.Experiment.Type.EXPERIMENT) - .build() - ) + CodeBundle.Location.Experiment.builder() + .evalName("eval_name") + .position( + CodeBundle.Location.Experiment.Position.Type.builder() + .type(CodeBundle.Location.Experiment.Position.Type.InnerType.TASK) + .build() + ) + .type(CodeBundle.Location.Experiment.Type.EXPERIMENT) + .build() ) .runtimeContext( CodeBundle.RuntimeContext.builder() @@ -33,7 +33,7 @@ class CodeBundleTest { ) .preview("preview") .build() - assertThat(codeBundle).isNotNull + assertThat(codeBundle.bundleId()).isEqualTo("bundle_id") assertThat(codeBundle.location()) .isEqualTo( @@ -41,9 +41,9 @@ class CodeBundleTest { CodeBundle.Location.Experiment.builder() .evalName("eval_name") .position( - CodeBundle.Location.Experiment.Position.ofTask( - Task.builder().type(Task.Type.TASK).build() - ) + CodeBundle.Location.Experiment.Position.Type.builder() + .type(CodeBundle.Location.Experiment.Position.Type.InnerType.TASK) + .build() ) .type(CodeBundle.Location.Experiment.Type.EXPERIMENT) .build() @@ -58,4 +58,39 @@ class CodeBundleTest { ) assertThat(codeBundle.preview()).isEqualTo("preview") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val codeBundle = + CodeBundle.builder() + .bundleId("bundle_id") + .location( + CodeBundle.Location.Experiment.builder() + .evalName("eval_name") + .position( + CodeBundle.Location.Experiment.Position.Type.builder() + .type(CodeBundle.Location.Experiment.Position.Type.InnerType.TASK) + .build() + ) + .type(CodeBundle.Location.Experiment.Type.EXPERIMENT) + .build() + ) + .runtimeContext( + CodeBundle.RuntimeContext.builder() + .runtime(CodeBundle.RuntimeContext.Runtime.NODE) + .version("version") + .build() + ) + .preview("preview") + .build() + + val roundtrippedCodeBundle = + jsonMapper.readValue( + jsonMapper.writeValueAsString(codeBundle), + jacksonTypeRef(), + ) + + assertThat(roundtrippedCodeBundle).isEqualTo(codeBundle) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CreateApiKeyOutputTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CreateApiKeyOutputTest.kt index cad34456..41a8261e 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CreateApiKeyOutputTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CreateApiKeyOutputTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class CreateApiKeyOutputTest { +internal class CreateApiKeyOutputTest { @Test - fun createCreateApiKeyOutput() { + fun create() { val createApiKeyOutput = CreateApiKeyOutput.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -20,7 +22,7 @@ class CreateApiKeyOutputTest { .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(createApiKeyOutput).isNotNull + assertThat(createApiKeyOutput.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(createApiKeyOutput.key()).isEqualTo("key") assertThat(createApiKeyOutput.name()).isEqualTo("name") @@ -30,4 +32,27 @@ class CreateApiKeyOutputTest { assertThat(createApiKeyOutput.orgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(createApiKeyOutput.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val createApiKeyOutput = + CreateApiKeyOutput.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .key("key") + .name("name") + .previewName("preview_name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedCreateApiKeyOutput = + jsonMapper.readValue( + jsonMapper.writeValueAsString(createApiKeyOutput), + jacksonTypeRef(), + ) + + assertThat(roundtrippedCreateApiKeyOutput).isEqualTo(createApiKeyOutput) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponseTest.kt index 81efff33..7799a635 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/CrossObjectInsertResponseTest.kt @@ -2,25 +2,110 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class CrossObjectInsertResponseTest { +internal class CrossObjectInsertResponseTest { @Test - fun createCrossObjectInsertResponse() { + fun create() { val crossObjectInsertResponse = CrossObjectInsertResponse.builder() - .dataset(CrossObjectInsertResponse.Dataset.builder().build()) - .experiment(CrossObjectInsertResponse.Experiment.builder().build()) - .projectLogs(CrossObjectInsertResponse.ProjectLogs.builder().build()) + .dataset( + CrossObjectInsertResponse.Dataset.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) + .experiment( + CrossObjectInsertResponse.Experiment.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) + .projectLogs( + CrossObjectInsertResponse.ProjectLogs.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) .build() - assertThat(crossObjectInsertResponse).isNotNull + assertThat(crossObjectInsertResponse.dataset()) - .isEqualTo(CrossObjectInsertResponse.Dataset.builder().build()) + .isEqualTo( + CrossObjectInsertResponse.Dataset.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) assertThat(crossObjectInsertResponse.experiment()) - .isEqualTo(CrossObjectInsertResponse.Experiment.builder().build()) + .isEqualTo( + CrossObjectInsertResponse.Experiment.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) assertThat(crossObjectInsertResponse.projectLogs()) - .isEqualTo(CrossObjectInsertResponse.ProjectLogs.builder().build()) + .isEqualTo( + CrossObjectInsertResponse.ProjectLogs.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val crossObjectInsertResponse = + CrossObjectInsertResponse.builder() + .dataset( + CrossObjectInsertResponse.Dataset.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) + .experiment( + CrossObjectInsertResponse.Experiment.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) + .projectLogs( + CrossObjectInsertResponse.ProjectLogs.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("row_ids" to listOf("string"))), + ) + .build() + ) + .build() + + val roundtrippedCrossObjectInsertResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(crossObjectInsertResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedCrossObjectInsertResponse).isEqualTo(crossObjectInsertResponse) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DataSummaryTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DataSummaryTest.kt index 544c8f05..40a33b54 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DataSummaryTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DataSummaryTest.kt @@ -2,15 +2,31 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DataSummaryTest { +internal class DataSummaryTest { @Test - fun createDataSummary() { - val dataSummary = DataSummary.builder().totalRecords(123L).build() - assertThat(dataSummary).isNotNull - assertThat(dataSummary.totalRecords()).isEqualTo(123L) + fun create() { + val dataSummary = DataSummary.builder().totalRecords(0L).build() + + assertThat(dataSummary.totalRecords()).isEqualTo(0L) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val dataSummary = DataSummary.builder().totalRecords(0L).build() + + val roundtrippedDataSummary = + jsonMapper.readValue( + jsonMapper.writeValueAsString(dataSummary), + jacksonTypeRef(), + ) + + assertThat(roundtrippedDataSummary).isEqualTo(dataSummary) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetCreateParamsTest.kt index cd299934..cfa031e9 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetCreateParamsTest.kt @@ -2,46 +2,64 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetCreateParamsTest { +internal class DatasetCreateParamsTest { @Test - fun createDatasetCreateParams() { + fun create() { DatasetCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") + .metadata( + DatasetCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() } @Test - fun getBody() { + fun body() { val params = DatasetCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") + .metadata( + DatasetCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.description()).isEqualTo("description") + assertThat(body.metadata()) + .isEqualTo( + DatasetCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = DatasetCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetDeleteParamsTest.kt index bb209233..87b85a35 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetDeleteParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetDeleteParamsTest { +internal class DatasetDeleteParamsTest { @Test - fun createDatasetDeleteParams() { + fun create() { DatasetDeleteParams.builder().datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = DatasetDeleteParams.builder().datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetEventTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetEventTest.kt index 6b0314e4..882a1962 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetEventTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetEventTest.kt @@ -2,15 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetEventTest { +internal class DatasetEventTest { @Test - fun createDatasetEvent() { + fun create() { val datasetEvent = DatasetEvent.builder() .id("id") @@ -20,12 +22,22 @@ class DatasetEventTest { .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .rootSpanId("root_span_id") .spanId("span_id") - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(DatasetEvent.Metadata.builder().build()) - .tags(listOf("string")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(DatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .addTag("string") .build() - assertThat(datasetEvent).isNotNull + assertThat(datasetEvent.id()).isEqualTo("id") assertThat(datasetEvent._xactId()).isEqualTo("_xact_id") assertThat(datasetEvent.created()) @@ -34,9 +46,58 @@ class DatasetEventTest { assertThat(datasetEvent.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(datasetEvent.rootSpanId()).isEqualTo("root_span_id") assertThat(datasetEvent.spanId()).isEqualTo("span_id") - assertThat(datasetEvent._expected()).isEqualTo(JsonNull.of()) - assertThat(datasetEvent._input()).isEqualTo(JsonNull.of()) - assertThat(datasetEvent.metadata()).isEqualTo(DatasetEvent.Metadata.builder().build()) + assertThat(datasetEvent._expected()).isEqualTo(JsonValue.from(mapOf())) + assertThat(datasetEvent._input()).isEqualTo(JsonValue.from(mapOf())) + assertThat(datasetEvent.isRoot()).isEqualTo(true) + assertThat(datasetEvent.metadata()) + .isEqualTo(DatasetEvent.Metadata.builder().model("model").build()) + assertThat(datasetEvent.origin()) + .isEqualTo( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) assertThat(datasetEvent.tags()).containsExactly("string") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val datasetEvent = + DatasetEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(DatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .addTag("string") + .build() + + val roundtrippedDatasetEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(datasetEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedDatasetEvent).isEqualTo(datasetEvent) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFeedbackParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFeedbackParamsTest.kt index e5ec92fd..383af384 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFeedbackParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFeedbackParamsTest.kt @@ -2,84 +2,93 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetFeedbackParamsTest { +internal class DatasetFeedbackParamsTest { @Test - fun createDatasetFeedbackParams() { + fun create() { DatasetFeedbackParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackDatasetItem.builder() - .id("id") - .comment("comment") - .metadata(FeedbackDatasetItem.Metadata.builder().build()) - .source(FeedbackDatasetItem.Source.APP) - .build() - ) + .addFeedback( + FeedbackDatasetItem.builder() + .id("id") + .comment("comment") + .metadata( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .source(FeedbackDatasetItem.Source.APP) + .addTag("string") + .build() ) .build() } @Test - fun getBody() { + fun pathParams() { val params = DatasetFeedbackParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackDatasetItem.builder() - .id("id") - .comment("comment") - .metadata(FeedbackDatasetItem.Metadata.builder().build()) - .source(FeedbackDatasetItem.Source.APP) - .build() - ) - ) + .addFeedback(FeedbackDatasetItem.builder().id("id").build()) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.feedback()) - .isEqualTo( - listOf( - FeedbackDatasetItem.builder() - .id("id") - .comment("comment") - .metadata(FeedbackDatasetItem.Metadata.builder().build()) - .source(FeedbackDatasetItem.Source.APP) - .build() - ) - ) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = DatasetFeedbackParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback(listOf(FeedbackDatasetItem.builder().id("id").build())) + .addFeedback( + FeedbackDatasetItem.builder() + .id("id") + .comment("comment") + .metadata( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .source(FeedbackDatasetItem.Source.APP) + .addTag("string") + .build() + ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.feedback()) - .isEqualTo(listOf(FeedbackDatasetItem.builder().id("id").build())) + .containsExactly( + FeedbackDatasetItem.builder() + .id("id") + .comment("comment") + .metadata( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .source(FeedbackDatasetItem.Source.APP) + .addTag("string") + .build() + ) } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = DatasetFeedbackParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback(listOf(FeedbackDatasetItem.builder().id("id").build())) + .addFeedback(FeedbackDatasetItem.builder().id("id").build()) .build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.feedback()).containsExactly(FeedbackDatasetItem.builder().id("id").build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchParamsTest.kt index 260bb3bb..79504f72 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchParamsTest.kt @@ -2,17 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetFetchParamsTest { +internal class DatasetFetchParamsTest { @Test - fun createDatasetFetchParams() { + fun create() { DatasetFetchParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") @@ -20,39 +20,46 @@ class DatasetFetchParamsTest { } @Test - fun getQueryParams() { + fun pathParams() { + val params = + DatasetFetchParams.builder().datasetId("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 queryParams() { val params = DatasetFetchParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() - val expected = mutableMapOf>() - expected.put("limit", listOf("123")) - expected.put("max_root_span_id", listOf("max_root_span_id")) - expected.put("max_xact_id", listOf("max_xact_id")) - expected.put("version", listOf("version")) - assertThat(params.getQueryParams()).isEqualTo(expected) - } - @Test - fun getQueryParamsWithoutOptionalFields() { - val params = - DatasetFetchParams.builder().datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("limit", "0") + .put("max_root_span_id", "max_root_span_id") + .put("max_xact_id", "max_xact_id") + .put("version", "version") + .build() + ) } @Test - fun getPathParam() { + fun queryParamsWithoutOptionalFields() { val params = DatasetFetchParams.builder().datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchPostParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchPostParamsTest.kt index cc6494aa..51ad2e9e 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchPostParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetFetchPostParamsTest.kt @@ -2,28 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetFetchPostParamsTest { +internal class DatasetFetchPostParamsTest { @Test - fun createDatasetFetchPostParams() { + fun create() { DatasetFetchPostParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") @@ -31,64 +20,45 @@ class DatasetFetchPostParamsTest { } @Test - fun getBody() { + fun pathParams() { + val params = + DatasetFetchPostParams.builder() + .datasetId("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 body() { val params = DatasetFetchPostParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.cursor()).isEqualTo("cursor") - assertThat(body.filters()) - .isEqualTo( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - assertThat(body.limit()).isEqualTo(123L) + assertThat(body.limit()).isEqualTo(0L) assertThat(body.maxRootSpanId()).isEqualTo("max_root_span_id") assertThat(body.maxXactId()).isEqualTo("max_xact_id") assertThat(body.version()).isEqualTo("version") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = DatasetFetchPostParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - DatasetFetchPostParams.builder() - .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetInsertParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetInsertParamsTest.kt index 69c688b4..09847227 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetInsertParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetInsertParamsTest.kt @@ -2,125 +2,133 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetInsertParamsTest { +internal class DatasetInsertParamsTest { @Test - fun createDatasetInsertParams() { + fun create() { DatasetInsertParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - DatasetInsertParams.Event.ofInsertDatasetEventReplace( - InsertDatasetEventReplace.builder() + .addEvent( + InsertDatasetEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertDatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertDatasetEventReplace.Metadata.builder().build()) - .tags(listOf("string")) + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") .build() ) - ) + .rootSpanId("root_span_id") + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() } @Test - fun getBody() { + fun pathParams() { val params = DatasetInsertParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - DatasetInsertParams.Event.ofInsertDatasetEventReplace( - InsertDatasetEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertDatasetEventReplace.Metadata.builder().build()) - .tags(listOf("string")) - .build() - ) - ) - ) + .addEvent(InsertDatasetEvent.builder().build()) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.events()) - .isEqualTo( - listOf( - DatasetInsertParams.Event.ofInsertDatasetEventReplace( - InsertDatasetEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertDatasetEventReplace.Metadata.builder().build()) - .tags(listOf("string")) - .build() - ) - ) - ) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = DatasetInsertParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - DatasetInsertParams.Event.ofInsertDatasetEventReplace( - InsertDatasetEventReplace.builder().build() + .addEvent( + InsertDatasetEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertDatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() ) - ) + .rootSpanId("root_span_id") + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.events()) - .isEqualTo( - listOf( - DatasetInsertParams.Event.ofInsertDatasetEventReplace( - InsertDatasetEventReplace.builder().build() + .containsExactly( + InsertDatasetEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertDatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() ) - ) + .rootSpanId("root_span_id") + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = DatasetInsertParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - DatasetInsertParams.Event.ofInsertDatasetEventReplace( - InsertDatasetEventReplace.builder().build() - ) - ) - ) + .addEvent(InsertDatasetEvent.builder().build()) .build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.events()).containsExactly(InsertDatasetEvent.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetListPageResponseTest.kt new file mode 100644 index 00000000..af744573 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetListPageResponseTest.kt @@ -0,0 +1,86 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class DatasetListPageResponseTest { + + @Test + fun create() { + val datasetListPageResponse = + DatasetListPageResponse.builder() + .addObject( + Dataset.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Dataset.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(datasetListPageResponse.objects()) + .containsExactly( + Dataset.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Dataset.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val datasetListPageResponse = + DatasetListPageResponse.builder() + .addObject( + Dataset.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Dataset.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedDatasetListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(datasetListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedDatasetListPageResponse).isEqualTo(datasetListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetListParamsTest.kt index d0963d5e..a6ffbbd4 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetListParamsTest.kt @@ -2,19 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetListParamsTest { +internal class DatasetListParamsTest { @Test - fun createDatasetListParams() { + fun create() { DatasetListParams.builder() .datasetName("dataset_name") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(DatasetListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") @@ -23,39 +23,42 @@ class DatasetListParamsTest { } @Test - fun getQueryParams() { + fun queryParams() { val params = DatasetListParams.builder() .datasetName("dataset_name") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(DatasetListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("dataset_name", listOf("dataset_name")) - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf( - DatasetListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("dataset_name", "dataset_name") + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("project_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("project_name", "project_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("project_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("project_name", listOf("project_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = DatasetListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetRetrieveParamsTest.kt index 776cce3b..1cdff551 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetRetrieveParamsTest.kt @@ -2,27 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetRetrieveParamsTest { +internal class DatasetRetrieveParamsTest { @Test - fun createDatasetRetrieveParams() { + fun create() { DatasetRetrieveParams.builder().datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = DatasetRetrieveParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetSummarizeParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetSummarizeParamsTest.kt index db5cbef2..49062a2c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetSummarizeParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetSummarizeParamsTest.kt @@ -2,14 +2,14 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetSummarizeParamsTest { +internal class DatasetSummarizeParamsTest { @Test - fun createDatasetSummarizeParams() { + fun create() { DatasetSummarizeParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .summarizeData(true) @@ -17,37 +17,40 @@ class DatasetSummarizeParamsTest { } @Test - fun getQueryParams() { + fun pathParams() { val params = DatasetSummarizeParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .summarizeData(true) .build() - val expected = mutableMapOf>() - expected.put("summarize_data", listOf("true")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParams() { val params = DatasetSummarizeParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .summarizeData(true) .build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo(QueryParams.builder().put("summarize_data", "true").build()) } @Test - fun getPathParam() { + fun queryParamsWithoutOptionalFields() { val params = DatasetSummarizeParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetTest.kt index da5d3f80..04678a9a 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetTest.kt @@ -2,14 +2,17 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetTest { +internal class DatasetTest { @Test - fun createDataset() { + fun create() { val dataset = Dataset.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -18,17 +21,51 @@ class DatasetTest { .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .description("description") - .metadata(Dataset.Metadata.builder().build()) + .metadata( + Dataset.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(dataset).isNotNull + assertThat(dataset.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(dataset.name()).isEqualTo("name") assertThat(dataset.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(dataset.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(dataset.deletedAt()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(dataset.description()).isEqualTo("description") - assertThat(dataset.metadata()).isEqualTo(Dataset.Metadata.builder().build()) + assertThat(dataset.metadata()) + .isEqualTo( + Dataset.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(dataset.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val dataset = + Dataset.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Dataset.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedDataset = + jsonMapper.readValue(jsonMapper.writeValueAsString(dataset), jacksonTypeRef()) + + assertThat(roundtrippedDataset).isEqualTo(dataset) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetUpdateParamsTest.kt index e8dfdbe0..c2d80638 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/DatasetUpdateParamsTest.kt @@ -2,54 +2,67 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class DatasetUpdateParamsTest { +internal class DatasetUpdateParamsTest { @Test - fun createDatasetUpdateParams() { + fun create() { DatasetUpdateParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .metadata(DatasetUpdateParams.Metadata.builder().build()) + .metadata( + DatasetUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .build() } @Test - fun getBody() { + fun pathParams() { + val params = + DatasetUpdateParams.builder().datasetId("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 body() { val params = DatasetUpdateParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .metadata(DatasetUpdateParams.Metadata.builder().build()) + .metadata( + DatasetUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.description()).isEqualTo("description") - assertThat(body.metadata()).isEqualTo(DatasetUpdateParams.Metadata.builder().build()) + assertThat(body.metadata()) + .isEqualTo( + DatasetUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(body.name()).isEqualTo("name") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = DatasetUpdateParams.builder().datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - DatasetUpdateParams.builder().datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "datasetId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarCreateParamsTest.kt index 7700b365..9e3df651 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarCreateParamsTest.kt @@ -2,14 +2,13 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarCreateParamsTest { +internal class EnvVarCreateParamsTest { @Test - fun createEnvVarCreateParams() { + fun create() { EnvVarCreateParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -19,7 +18,7 @@ class EnvVarCreateParamsTest { } @Test - fun getBody() { + fun body() { val params = EnvVarCreateParams.builder() .name("name") @@ -27,8 +26,9 @@ class EnvVarCreateParamsTest { .objectType(EnvVarCreateParams.ObjectType.ORGANIZATION) .value("value") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.objectType()).isEqualTo(EnvVarCreateParams.ObjectType.ORGANIZATION) @@ -36,15 +36,16 @@ class EnvVarCreateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = EnvVarCreateParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectType(EnvVarCreateParams.ObjectType.ORGANIZATION) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.objectType()).isEqualTo(EnvVarCreateParams.ObjectType.ORGANIZATION) diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarDeleteParamsTest.kt index 29879f19..80887f78 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarDeleteParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarDeleteParamsTest { +internal class EnvVarDeleteParamsTest { @Test - fun createEnvVarDeleteParams() { + fun create() { EnvVarDeleteParams.builder().envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = EnvVarDeleteParams.builder().envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "envVarId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListParamsTest.kt index f95a36d6..4978303f 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListParamsTest.kt @@ -2,49 +2,54 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarListParamsTest { +internal class EnvVarListParamsTest { @Test - fun createEnvVarListParams() { + fun create() { EnvVarListParams.builder() .envVarName("env_var_name") - .ids(EnvVarListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(EnvVarListParams.ObjectType.ORGANIZATION) + .objectType(EnvVarObjectType.ORGANIZATION) .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = EnvVarListParams.builder() .envVarName("env_var_name") - .ids(EnvVarListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(EnvVarListParams.ObjectType.ORGANIZATION) + .objectType(EnvVarObjectType.ORGANIZATION) .build() - val expected = mutableMapOf>() - expected.put("env_var_name", listOf("env_var_name")) - expected.put( - "ids", - listOf(EnvVarListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("object_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("object_type", listOf(EnvVarListParams.ObjectType.ORGANIZATION.toString())) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("env_var_name", "env_var_name") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("object_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("object_type", "organization") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = EnvVarListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListResponseTest.kt index 0024324f..d10c2868 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarListResponseTest.kt @@ -2,30 +2,30 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarListResponseTest { +internal class EnvVarListResponseTest { @Test - fun createEnvVarListResponse() { + fun create() { val envVarListResponse = EnvVarListResponse.builder() - .objects( - listOf( - EnvVar.builder() - .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .name("name") - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(EnvVar.ObjectType.ORGANIZATION) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .used(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .build() - ) + .addObject( + EnvVar.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(EnvVar.ObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .used(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() ) .build() - assertThat(envVarListResponse).isNotNull + assertThat(envVarListResponse.objects()) .containsExactly( EnvVar.builder() @@ -38,4 +38,30 @@ class EnvVarListResponseTest { .build() ) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val envVarListResponse = + EnvVarListResponse.builder() + .addObject( + EnvVar.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(EnvVar.ObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .used(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + ) + .build() + + val roundtrippedEnvVarListResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(envVarListResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedEnvVarListResponse).isEqualTo(envVarListResponse) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarReplaceParamsTest.kt index 7be569fb..c6499a7d 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarReplaceParamsTest.kt @@ -2,14 +2,13 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarReplaceParamsTest { +internal class EnvVarReplaceParamsTest { @Test - fun createEnvVarReplaceParams() { + fun create() { EnvVarReplaceParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -19,7 +18,7 @@ class EnvVarReplaceParamsTest { } @Test - fun getBody() { + fun body() { val params = EnvVarReplaceParams.builder() .name("name") @@ -27,8 +26,9 @@ class EnvVarReplaceParamsTest { .objectType(EnvVarReplaceParams.ObjectType.ORGANIZATION) .value("value") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.objectType()).isEqualTo(EnvVarReplaceParams.ObjectType.ORGANIZATION) @@ -36,15 +36,16 @@ class EnvVarReplaceParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = EnvVarReplaceParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectType(EnvVarReplaceParams.ObjectType.ORGANIZATION) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.objectType()).isEqualTo(EnvVarReplaceParams.ObjectType.ORGANIZATION) diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParamsTest.kt index 52c6148b..b3cefe22 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarRetrieveParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarRetrieveParamsTest { +internal class EnvVarRetrieveParamsTest { @Test - fun createEnvVarRetrieveParams() { + fun create() { EnvVarRetrieveParams.builder().envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = EnvVarRetrieveParams.builder().envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "envVarId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarTest.kt index d4bf3390..7ae3a54e 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarTest { +internal class EnvVarTest { @Test - fun createEnvVar() { + fun create() { val envVar = EnvVar.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -19,7 +21,7 @@ class EnvVarTest { .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .used(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .build() - assertThat(envVar).isNotNull + assertThat(envVar.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(envVar.name()).isEqualTo("name") assertThat(envVar.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -27,4 +29,23 @@ class EnvVarTest { assertThat(envVar.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(envVar.used()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val envVar = + EnvVar.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(EnvVar.ObjectType.ORGANIZATION) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .used(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .build() + + val roundtrippedEnvVar = + jsonMapper.readValue(jsonMapper.writeValueAsString(envVar), jacksonTypeRef()) + + assertThat(roundtrippedEnvVar).isEqualTo(envVar) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarUpdateParamsTest.kt index 3ebce16f..8c2adcf7 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EnvVarUpdateParamsTest.kt @@ -2,14 +2,13 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EnvVarUpdateParamsTest { +internal class EnvVarUpdateParamsTest { @Test - fun createEnvVarUpdateParams() { + fun create() { EnvVarUpdateParams.builder() .envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") @@ -18,42 +17,43 @@ class EnvVarUpdateParamsTest { } @Test - fun getBody() { + fun pathParams() { val params = EnvVarUpdateParams.builder() .envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") - .value("value") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") - assertThat(body.value()).isEqualTo("value") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = EnvVarUpdateParams.builder() .envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") + .value("value") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") + assertThat(body.value()).isEqualTo("value") } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = EnvVarUpdateParams.builder() .envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") .build() - assertThat(params).isNotNull - // path param "envVarId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.name()).isEqualTo("name") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EvalCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EvalCreateParamsTest.kt index 84d240e6..73bb6398 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EvalCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/EvalCreateParamsTest.kt @@ -2,95 +2,198 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class EvalCreateParamsTest { +internal class EvalCreateParamsTest { @Test - fun createEvalCreateParams() { + fun create() { EvalCreateParams.builder() .data( - EvalCreateParams.Data.ofDatasetId( - EvalCreateParams.Data.DatasetId.builder().datasetId("dataset_id").build() - ) - ) - .projectId("project_id") - .scores( - listOf( - EvalCreateParams.Score.ofFunctionId( - EvalCreateParams.Score.FunctionId.builder() - .functionId("function_id") - .version("version") + EvalCreateParams.Data.DatasetId.builder() + .datasetId("dataset_id") + ._internalBtql( + EvalCreateParams.Data.DatasetId._InternalBtql + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) - ) + .build() + ) + .projectId("project_id") + .addScore( + EvalCreateParams.Score.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() ) .task( - EvalCreateParams.Task.ofFunctionId( - EvalCreateParams.Task.FunctionId.builder() - .functionId("function_id") - .version("version") - .build() - ) + EvalCreateParams.Task.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() ) + .baseExperimentId("base_experiment_id") + .baseExperimentName("base_experiment_name") .experimentName("experiment_name") - .metadata(EvalCreateParams.Metadata.builder().build()) + .gitMetadataSettings( + EvalCreateParams.GitMetadataSettings.builder() + .collect(EvalCreateParams.GitMetadataSettings.Collect.ALL) + .addField(EvalCreateParams.GitMetadataSettings.Field.COMMIT) + .build() + ) + .isPublic(true) + .maxConcurrency(0.0) + .metadata( + EvalCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .parent( + EvalCreateParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType(EvalCreateParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS) + .propagatedEvent( + EvalCreateParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + EvalCreateParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) .stream(true) + .timeout(0.0) + .trialCount(0.0) .build() } @Test - fun getBody() { + fun body() { val params = EvalCreateParams.builder() .data( - EvalCreateParams.Data.ofDatasetId( - EvalCreateParams.Data.DatasetId.builder().datasetId("dataset_id").build() - ) - ) - .projectId("project_id") - .scores( - listOf( - EvalCreateParams.Score.ofFunctionId( - EvalCreateParams.Score.FunctionId.builder() - .functionId("function_id") - .version("version") + EvalCreateParams.Data.DatasetId.builder() + .datasetId("dataset_id") + ._internalBtql( + EvalCreateParams.Data.DatasetId._InternalBtql + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) - ) + .build() + ) + .projectId("project_id") + .addScore( + EvalCreateParams.Score.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() ) .task( - EvalCreateParams.Task.ofFunctionId( - EvalCreateParams.Task.FunctionId.builder() - .functionId("function_id") - .version("version") - .build() - ) + EvalCreateParams.Task.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() ) + .baseExperimentId("base_experiment_id") + .baseExperimentName("base_experiment_name") .experimentName("experiment_name") - .metadata(EvalCreateParams.Metadata.builder().build()) + .gitMetadataSettings( + EvalCreateParams.GitMetadataSettings.builder() + .collect(EvalCreateParams.GitMetadataSettings.Collect.ALL) + .addField(EvalCreateParams.GitMetadataSettings.Field.COMMIT) + .build() + ) + .isPublic(true) + .maxConcurrency(0.0) + .metadata( + EvalCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .parent( + EvalCreateParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType( + EvalCreateParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS + ) + .propagatedEvent( + EvalCreateParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + EvalCreateParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) .stream(true) + .timeout(0.0) + .trialCount(0.0) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.data()) .isEqualTo( EvalCreateParams.Data.ofDatasetId( - EvalCreateParams.Data.DatasetId.builder().datasetId("dataset_id").build() + EvalCreateParams.Data.DatasetId.builder() + .datasetId("dataset_id") + ._internalBtql( + EvalCreateParams.Data.DatasetId._InternalBtql + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() ) ) assertThat(body.projectId()).isEqualTo("project_id") assertThat(body.scores()) - .isEqualTo( - listOf( - EvalCreateParams.Score.ofFunctionId( - EvalCreateParams.Score.FunctionId.builder() - .functionId("function_id") - .version("version") - .build() - ) + .containsExactly( + EvalCreateParams.Score.ofFunctionId( + EvalCreateParams.Score.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() ) ) assertThat(body.task()) @@ -102,38 +205,80 @@ class EvalCreateParamsTest { .build() ) ) + assertThat(body.baseExperimentId()).isEqualTo("base_experiment_id") + assertThat(body.baseExperimentName()).isEqualTo("base_experiment_name") assertThat(body.experimentName()).isEqualTo("experiment_name") - assertThat(body.metadata()).isEqualTo(EvalCreateParams.Metadata.builder().build()) + assertThat(body.gitMetadataSettings()) + .isEqualTo( + EvalCreateParams.GitMetadataSettings.builder() + .collect(EvalCreateParams.GitMetadataSettings.Collect.ALL) + .addField(EvalCreateParams.GitMetadataSettings.Field.COMMIT) + .build() + ) + assertThat(body.isPublic()).isEqualTo(true) + assertThat(body.maxConcurrency()).isEqualTo(0.0) + assertThat(body.metadata()) + .isEqualTo( + EvalCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + assertThat(body.parent()) + .isEqualTo( + EvalCreateParams.Parent.ofSpanParentStruct( + EvalCreateParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType( + EvalCreateParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS + ) + .propagatedEvent( + EvalCreateParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + EvalCreateParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() + ) + ) + assertThat(body.repoInfo()) + .isEqualTo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) assertThat(body.stream()).isEqualTo(true) + assertThat(body.timeout()).isEqualTo(0.0) + assertThat(body.trialCount()).isEqualTo(0.0) } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = EvalCreateParams.builder() - .data( - EvalCreateParams.Data.ofDatasetId( - EvalCreateParams.Data.DatasetId.builder().datasetId("dataset_id").build() - ) - ) + .data(EvalCreateParams.Data.DatasetId.builder().datasetId("dataset_id").build()) .projectId("project_id") - .scores( - listOf( - EvalCreateParams.Score.ofFunctionId( - EvalCreateParams.Score.FunctionId.builder() - .functionId("function_id") - .build() - ) - ) - ) - .task( - EvalCreateParams.Task.ofFunctionId( - EvalCreateParams.Task.FunctionId.builder().functionId("function_id").build() - ) + .addScore( + EvalCreateParams.Score.FunctionId.builder().functionId("function_id").build() ) + .task(EvalCreateParams.Task.FunctionId.builder().functionId("function_id").build()) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.data()) .isEqualTo( EvalCreateParams.Data.ofDatasetId( @@ -142,13 +287,9 @@ class EvalCreateParamsTest { ) assertThat(body.projectId()).isEqualTo("project_id") assertThat(body.scores()) - .isEqualTo( - listOf( - EvalCreateParams.Score.ofFunctionId( - EvalCreateParams.Score.FunctionId.builder() - .functionId("function_id") - .build() - ) + .containsExactly( + EvalCreateParams.Score.ofFunctionId( + EvalCreateParams.Score.FunctionId.builder().functionId("function_id").build() ) ) assertThat(body.task()) diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentCreateParamsTest.kt index 35e96747..f7336ef6 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentCreateParamsTest.kt @@ -2,14 +2,14 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentCreateParamsTest { +internal class ExperimentCreateParamsTest { @Test - fun createExperimentCreateParams() { + fun create() { ExperimentCreateParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -17,8 +17,12 @@ class ExperimentCreateParamsTest { .datasetVersion("dataset_version") .description("description") .ensureNew(true) - .metadata(ExperimentCreateParams.Metadata.builder().build()) - .name("name") + .metadata( + ExperimentCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("x") .public_(true) .repoInfo( RepoInfo.builder() @@ -37,7 +41,7 @@ class ExperimentCreateParamsTest { } @Test - fun getBody() { + fun body() { val params = ExperimentCreateParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -46,8 +50,12 @@ class ExperimentCreateParamsTest { .datasetVersion("dataset_version") .description("description") .ensureNew(true) - .metadata(ExperimentCreateParams.Metadata.builder().build()) - .name("name") + .metadata( + ExperimentCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("x") .public_(true) .repoInfo( RepoInfo.builder() @@ -63,16 +71,22 @@ class ExperimentCreateParamsTest { .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.baseExpId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.datasetId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.datasetVersion()).isEqualTo("dataset_version") assertThat(body.description()).isEqualTo("description") assertThat(body.ensureNew()).isEqualTo(true) - assertThat(body.metadata()).isEqualTo(ExperimentCreateParams.Metadata.builder().build()) - assertThat(body.name()).isEqualTo("name") + assertThat(body.metadata()) + .isEqualTo( + ExperimentCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + assertThat(body.name()).isEqualTo("x") assertThat(body.public_()).isEqualTo(true) assertThat(body.repoInfo()) .isEqualTo( @@ -91,13 +105,14 @@ class ExperimentCreateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ExperimentCreateParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentDeleteParamsTest.kt index 4577db52..d3aa984d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentDeleteParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentDeleteParamsTest { +internal class ExperimentDeleteParamsTest { @Test - fun createExperimentDeleteParams() { + fun create() { ExperimentDeleteParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = ExperimentDeleteParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentEventTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentEventTest.kt index c76ebc13..596cd7d3 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentEventTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentEventTest.kt @@ -2,15 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentEventTest { +internal class ExperimentEventTest { @Test - fun createExperimentEvent() { + fun create() { val experimentEvent = ExperimentEvent.builder() .id("id") @@ -24,35 +26,46 @@ class ExperimentEventTest { ExperimentEvent.Context.builder() .callerFilename("caller_filename") .callerFunctionname("caller_functionname") - .callerLineno(123L) + .callerLineno(0L) .build() ) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(ExperimentEvent.Metadata.builder().build()) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ExperimentEvent.Metadata.builder().model("model").build()) .metrics( ExperimentEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) .build() ) - .output(JsonNull.of()) - .scores(ExperimentEvent.Scores.builder().build()) - .spanAttributes( - ExperimentEvent.SpanAttributes.builder() - .name("name") - .type(ExperimentEvent.SpanAttributes.Type.LLM) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") .build() ) - .spanParents(listOf("string")) - .tags(listOf("string")) + .output(JsonValue.from(mapOf())) + .scores( + ExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .addSpanParent("string") + .addTag("string") .build() - assertThat(experimentEvent).isNotNull + assertThat(experimentEvent.id()).isEqualTo("id") assertThat(experimentEvent._xactId()).isEqualTo("_xact_id") assertThat(experimentEvent.created()) @@ -66,34 +79,113 @@ class ExperimentEventTest { ExperimentEvent.Context.builder() .callerFilename("caller_filename") .callerFunctionname("caller_functionname") - .callerLineno(123L) + .callerLineno(0L) .build() ) - assertThat(experimentEvent.datasetRecordId()).isEqualTo("dataset_record_id") - assertThat(experimentEvent._error()).isEqualTo(JsonNull.of()) - assertThat(experimentEvent._expected()).isEqualTo(JsonNull.of()) - assertThat(experimentEvent._input()).isEqualTo(JsonNull.of()) - assertThat(experimentEvent.metadata()).isEqualTo(ExperimentEvent.Metadata.builder().build()) + assertThat(experimentEvent._error()).isEqualTo(JsonValue.from(mapOf())) + assertThat(experimentEvent._expected()).isEqualTo(JsonValue.from(mapOf())) + assertThat(experimentEvent._input()).isEqualTo(JsonValue.from(mapOf())) + assertThat(experimentEvent.isRoot()).isEqualTo(true) + assertThat(experimentEvent.metadata()) + .isEqualTo(ExperimentEvent.Metadata.builder().model("model").build()) assertThat(experimentEvent.metrics()) .isEqualTo( ExperimentEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) .build() ) - assertThat(experimentEvent._output()).isEqualTo(JsonNull.of()) - assertThat(experimentEvent.scores()).isEqualTo(ExperimentEvent.Scores.builder().build()) - assertThat(experimentEvent.spanAttributes()) + assertThat(experimentEvent.origin()) + .isEqualTo( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + assertThat(experimentEvent._output()).isEqualTo(JsonValue.from(mapOf())) + assertThat(experimentEvent.scores()) .isEqualTo( - ExperimentEvent.SpanAttributes.builder() - .name("name") - .type(ExperimentEvent.SpanAttributes.Type.LLM) + ExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) .build() ) + assertThat(experimentEvent.spanAttributes()) + .isEqualTo(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) assertThat(experimentEvent.spanParents()).containsExactly("string") assertThat(experimentEvent.tags()).containsExactly("string") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val experimentEvent = + ExperimentEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .context( + ExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + ExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .addSpanParent("string") + .addTag("string") + .build() + + val roundtrippedExperimentEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(experimentEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedExperimentEvent).isEqualTo(experimentEvent) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParamsTest.kt index b05c51e5..ed20850d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFeedbackParamsTest.kt @@ -2,91 +2,112 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentFeedbackParamsTest { +internal class ExperimentFeedbackParamsTest { @Test - fun createExperimentFeedbackParams() { + fun create() { ExperimentFeedbackParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackExperimentItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackExperimentItem.Metadata.builder().build()) - .scores(FeedbackExperimentItem.Scores.builder().build()) - .source(FeedbackExperimentItem.Source.APP) - .build() - ) + .addFeedback( + FeedbackExperimentItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackExperimentItem.Source.APP) + .addTag("string") + .build() ) .build() } @Test - fun getBody() { + fun pathParams() { val params = ExperimentFeedbackParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackExperimentItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackExperimentItem.Metadata.builder().build()) - .scores(FeedbackExperimentItem.Scores.builder().build()) - .source(FeedbackExperimentItem.Source.APP) - .build() - ) - ) + .addFeedback(FeedbackExperimentItem.builder().id("id").build()) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.feedback()) - .isEqualTo( - listOf( - FeedbackExperimentItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackExperimentItem.Metadata.builder().build()) - .scores(FeedbackExperimentItem.Scores.builder().build()) - .source(FeedbackExperimentItem.Source.APP) - .build() - ) - ) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = ExperimentFeedbackParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback(listOf(FeedbackExperimentItem.builder().id("id").build())) + .addFeedback( + FeedbackExperimentItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackExperimentItem.Source.APP) + .addTag("string") + .build() + ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.feedback()) - .isEqualTo(listOf(FeedbackExperimentItem.builder().id("id").build())) + .containsExactly( + FeedbackExperimentItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackExperimentItem.Source.APP) + .addTag("string") + .build() + ) } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = ExperimentFeedbackParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback(listOf(FeedbackExperimentItem.builder().id("id").build())) + .addFeedback(FeedbackExperimentItem.builder().id("id").build()) .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.feedback()) + .containsExactly(FeedbackExperimentItem.builder().id("id").build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchParamsTest.kt index 138cbb6a..70160fd1 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchParamsTest.kt @@ -2,17 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentFetchParamsTest { +internal class ExperimentFetchParamsTest { @Test - fun createExperimentFetchParams() { + fun create() { ExperimentFetchParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") @@ -20,43 +20,50 @@ class ExperimentFetchParamsTest { } @Test - fun getQueryParams() { + fun pathParams() { val params = ExperimentFetchParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) - .maxRootSpanId("max_root_span_id") - .maxXactId("max_xact_id") - .version("version") .build() - val expected = mutableMapOf>() - expected.put("limit", listOf("123")) - expected.put("max_root_span_id", listOf("max_root_span_id")) - expected.put("max_xact_id", listOf("max_xact_id")) - expected.put("version", listOf("version")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParams() { val params = ExperimentFetchParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") .build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("limit", "0") + .put("max_root_span_id", "max_root_span_id") + .put("max_xact_id", "max_xact_id") + .put("version", "version") + .build() + ) } @Test - fun getPathParam() { + fun queryParamsWithoutOptionalFields() { val params = ExperimentFetchParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParamsTest.kt index d48306d8..d7245859 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentFetchPostParamsTest.kt @@ -2,28 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentFetchPostParamsTest { +internal class ExperimentFetchPostParamsTest { @Test - fun createExperimentFetchPostParams() { + fun create() { ExperimentFetchPostParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") @@ -31,64 +20,45 @@ class ExperimentFetchPostParamsTest { } @Test - fun getBody() { + fun pathParams() { + val params = + ExperimentFetchPostParams.builder() + .experimentId("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 body() { val params = ExperimentFetchPostParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.cursor()).isEqualTo("cursor") - assertThat(body.filters()) - .isEqualTo( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - assertThat(body.limit()).isEqualTo(123L) + assertThat(body.limit()).isEqualTo(0L) assertThat(body.maxRootSpanId()).isEqualTo("max_root_span_id") assertThat(body.maxXactId()).isEqualTo("max_xact_id") assertThat(body.version()).isEqualTo("version") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ExperimentFetchPostParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - ExperimentFetchPostParams.builder() - .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentInsertParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentInsertParamsTest.kt index 80fced9c..105b8225 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentInsertParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentInsertParamsTest.kt @@ -2,203 +2,220 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentInsertParamsTest { +internal class ExperimentInsertParamsTest { @Test - fun createExperimentInsertParams() { + fun create() { ExperimentInsertParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ExperimentInsertParams.Event.ofInsertExperimentEventReplace( - InsertExperimentEventReplace.builder() + .addEvent( + InsertExperimentEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertExperimentEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertExperimentEventReplace.Metadata.builder().build()) - .metrics( - InsertExperimentEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertExperimentEventReplace.Scores.builder().build()) - .spanAttributes( - InsertExperimentEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertExperimentEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") .build() ) - ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() } @Test - fun getBody() { + fun pathParams() { val params = ExperimentInsertParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ExperimentInsertParams.Event.ofInsertExperimentEventReplace( - InsertExperimentEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertExperimentEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertExperimentEventReplace.Metadata.builder().build()) - .metrics( - InsertExperimentEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertExperimentEventReplace.Scores.builder().build()) - .spanAttributes( - InsertExperimentEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertExperimentEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - ) - ) - ) + .addEvent(InsertExperimentEvent.builder().build()) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.events()) - .isEqualTo( - listOf( - ExperimentInsertParams.Event.ofInsertExperimentEventReplace( - InsertExperimentEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertExperimentEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertExperimentEventReplace.Metadata.builder().build()) - .metrics( - InsertExperimentEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertExperimentEventReplace.Scores.builder().build()) - .spanAttributes( - InsertExperimentEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertExperimentEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - ) - ) - ) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = ExperimentInsertParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ExperimentInsertParams.Event.ofInsertExperimentEventReplace( - InsertExperimentEventReplace.builder().build() + .addEvent( + InsertExperimentEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() ) - ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.events()) - .isEqualTo( - listOf( - ExperimentInsertParams.Event.ofInsertExperimentEventReplace( - InsertExperimentEventReplace.builder().build() + .containsExactly( + InsertExperimentEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() ) - ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = ExperimentInsertParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ExperimentInsertParams.Event.ofInsertExperimentEventReplace( - InsertExperimentEventReplace.builder().build() - ) - ) - ) + .addEvent(InsertExperimentEvent.builder().build()) .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.events()).containsExactly(InsertExperimentEvent.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentListPageResponseTest.kt new file mode 100644 index 00000000..867711cd --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentListPageResponseTest.kt @@ -0,0 +1,140 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ExperimentListPageResponseTest { + + @Test + fun create() { + val experimentListPageResponse = + ExperimentListPageResponse.builder() + .addObject( + Experiment.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .public_(true) + .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .commit("commit") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetVersion("dataset_version") + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Experiment.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(experimentListPageResponse.objects()) + .containsExactly( + Experiment.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .public_(true) + .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .commit("commit") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetVersion("dataset_version") + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Experiment.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val experimentListPageResponse = + ExperimentListPageResponse.builder() + .addObject( + Experiment.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .public_(true) + .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .commit("commit") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetVersion("dataset_version") + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Experiment.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedExperimentListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(experimentListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedExperimentListPageResponse).isEqualTo(experimentListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentListParamsTest.kt index 2168e880..9c1814c3 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentListParamsTest.kt @@ -2,19 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentListParamsTest { +internal class ExperimentListParamsTest { @Test - fun createExperimentListParams() { + fun create() { ExperimentListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .experimentName("experiment_name") - .ids(ExperimentListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") @@ -23,39 +23,42 @@ class ExperimentListParamsTest { } @Test - fun getQueryParams() { + fun queryParams() { val params = ExperimentListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .experimentName("experiment_name") - .ids(ExperimentListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("experiment_name", listOf("experiment_name")) - expected.put( - "ids", - listOf( - ExperimentListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("experiment_name", "experiment_name") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("project_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("project_name", "project_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("project_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("project_name", listOf("project_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = ExperimentListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParamsTest.kt index 5efe0624..26795ef7 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentRetrieveParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentRetrieveParamsTest { +internal class ExperimentRetrieveParamsTest { @Test - fun createExperimentRetrieveParams() { + fun create() { ExperimentRetrieveParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = ExperimentRetrieveParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParamsTest.kt index d813806c..c5599fa2 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentSummarizeParamsTest.kt @@ -2,14 +2,14 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentSummarizeParamsTest { +internal class ExperimentSummarizeParamsTest { @Test - fun createExperimentSummarizeParams() { + fun create() { ExperimentSummarizeParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .comparisonExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -18,39 +18,46 @@ class ExperimentSummarizeParamsTest { } @Test - fun getQueryParams() { + fun pathParams() { val params = ExperimentSummarizeParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .comparisonExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .summarizeScores(true) .build() - val expected = mutableMapOf>() - expected.put("comparison_experiment_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("summarize_scores", listOf("true")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParams() { val params = ExperimentSummarizeParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .summarizeScores(true) .build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("comparison_experiment_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("summarize_scores", "true") + .build() + ) } @Test - fun getPathParam() { + fun queryParamsWithoutOptionalFields() { val params = ExperimentSummarizeParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentTest.kt index 430f4803..aef7080b 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentTest.kt @@ -2,14 +2,17 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentTest { +internal class ExperimentTest { @Test - fun createExperiment() { + fun create() { val experiment = Experiment.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -23,7 +26,11 @@ class ExperimentTest { .datasetVersion("dataset_version") .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .description("description") - .metadata(Experiment.Metadata.builder().build()) + .metadata( + Experiment.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .repoInfo( RepoInfo.builder() .authorEmail("author_email") @@ -39,7 +46,7 @@ class ExperimentTest { ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(experiment).isNotNull + assertThat(experiment.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(experiment.name()).isEqualTo("name") assertThat(experiment.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -52,7 +59,12 @@ class ExperimentTest { assertThat(experiment.deletedAt()) .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(experiment.description()).isEqualTo("description") - assertThat(experiment.metadata()).isEqualTo(Experiment.Metadata.builder().build()) + assertThat(experiment.metadata()) + .isEqualTo( + Experiment.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(experiment.repoInfo()) .isEqualTo( RepoInfo.builder() @@ -69,4 +81,50 @@ class ExperimentTest { ) assertThat(experiment.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val experiment = + Experiment.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .public_(true) + .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .commit("commit") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetVersion("dataset_version") + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .metadata( + Experiment.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedExperiment = + jsonMapper.readValue( + jsonMapper.writeValueAsString(experiment), + jacksonTypeRef(), + ) + + assertThat(roundtrippedExperiment).isEqualTo(experiment) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentUpdateParamsTest.kt index 22231f89..9a5b4c10 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ExperimentUpdateParamsTest.kt @@ -2,21 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ExperimentUpdateParamsTest { +internal class ExperimentUpdateParamsTest { @Test - fun createExperimentUpdateParams() { + fun create() { ExperimentUpdateParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .datasetVersion("dataset_version") .description("description") - .metadata(ExperimentUpdateParams.Metadata.builder().build()) + .metadata( + ExperimentUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .public_(true) .repoInfo( @@ -36,7 +40,19 @@ class ExperimentUpdateParamsTest { } @Test - fun getBody() { + fun pathParams() { + val params = + ExperimentUpdateParams.builder() + .experimentId("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 body() { val params = ExperimentUpdateParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -44,7 +60,11 @@ class ExperimentUpdateParamsTest { .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .datasetVersion("dataset_version") .description("description") - .metadata(ExperimentUpdateParams.Metadata.builder().build()) + .metadata( + ExperimentUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .public_(true) .repoInfo( @@ -61,13 +81,19 @@ class ExperimentUpdateParamsTest { .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.baseExpId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.datasetId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.datasetVersion()).isEqualTo("dataset_version") assertThat(body.description()).isEqualTo("description") - assertThat(body.metadata()).isEqualTo(ExperimentUpdateParams.Metadata.builder().build()) + assertThat(body.metadata()) + .isEqualTo( + ExperimentUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(body.name()).isEqualTo("name") assertThat(body.public_()).isEqualTo(true) assertThat(body.repoInfo()) @@ -87,25 +113,12 @@ class ExperimentUpdateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ExperimentUpdateParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - ExperimentUpdateParams.builder() - .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "experimentId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackDatasetItemTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackDatasetItemTest.kt index 75f6c727..09cd6568 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackDatasetItemTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackDatasetItemTest.kt @@ -2,25 +2,63 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FeedbackDatasetItemTest { +internal class FeedbackDatasetItemTest { @Test - fun createFeedbackDatasetItem() { + fun create() { val feedbackDatasetItem = FeedbackDatasetItem.builder() .id("id") .comment("comment") - .metadata(FeedbackDatasetItem.Metadata.builder().build()) + .metadata( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .source(FeedbackDatasetItem.Source.APP) + .addTag("string") .build() - assertThat(feedbackDatasetItem).isNotNull + assertThat(feedbackDatasetItem.id()).isEqualTo("id") assertThat(feedbackDatasetItem.comment()).isEqualTo("comment") assertThat(feedbackDatasetItem.metadata()) - .isEqualTo(FeedbackDatasetItem.Metadata.builder().build()) + .isEqualTo( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(feedbackDatasetItem.source()).isEqualTo(FeedbackDatasetItem.Source.APP) + assertThat(feedbackDatasetItem.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val feedbackDatasetItem = + FeedbackDatasetItem.builder() + .id("id") + .comment("comment") + .metadata( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .source(FeedbackDatasetItem.Source.APP) + .addTag("string") + .build() + + val roundtrippedFeedbackDatasetItem = + jsonMapper.readValue( + jsonMapper.writeValueAsString(feedbackDatasetItem), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFeedbackDatasetItem).isEqualTo(feedbackDatasetItem) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackExperimentItemTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackExperimentItemTest.kt index b55fbd3e..23e7139a 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackExperimentItemTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackExperimentItemTest.kt @@ -2,31 +2,83 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FeedbackExperimentItemTest { +internal class FeedbackExperimentItemTest { @Test - fun createFeedbackExperimentItem() { + fun create() { val feedbackExperimentItem = FeedbackExperimentItem.builder() .id("id") .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackExperimentItem.Metadata.builder().build()) - .scores(FeedbackExperimentItem.Scores.builder().build()) + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .source(FeedbackExperimentItem.Source.APP) + .addTag("string") .build() - assertThat(feedbackExperimentItem).isNotNull + assertThat(feedbackExperimentItem.id()).isEqualTo("id") assertThat(feedbackExperimentItem.comment()).isEqualTo("comment") - assertThat(feedbackExperimentItem._expected()).isEqualTo(JsonNull.of()) + assertThat(feedbackExperimentItem._expected()) + .isEqualTo(JsonValue.from(mapOf())) assertThat(feedbackExperimentItem.metadata()) - .isEqualTo(FeedbackExperimentItem.Metadata.builder().build()) + .isEqualTo( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(feedbackExperimentItem.scores()) - .isEqualTo(FeedbackExperimentItem.Scores.builder().build()) + .isEqualTo( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) assertThat(feedbackExperimentItem.source()).isEqualTo(FeedbackExperimentItem.Source.APP) + assertThat(feedbackExperimentItem.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val feedbackExperimentItem = + FeedbackExperimentItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackExperimentItem.Source.APP) + .addTag("string") + .build() + + val roundtrippedFeedbackExperimentItem = + jsonMapper.readValue( + jsonMapper.writeValueAsString(feedbackExperimentItem), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFeedbackExperimentItem).isEqualTo(feedbackExperimentItem) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItemTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItemTest.kt index 78451e5e..d3b7bcea 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItemTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackProjectLogsItemTest.kt @@ -2,31 +2,83 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FeedbackProjectLogsItemTest { +internal class FeedbackProjectLogsItemTest { @Test - fun createFeedbackProjectLogsItem() { + fun create() { val feedbackProjectLogsItem = FeedbackProjectLogsItem.builder() .id("id") .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackProjectLogsItem.Metadata.builder().build()) - .scores(FeedbackProjectLogsItem.Scores.builder().build()) + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .source(FeedbackProjectLogsItem.Source.APP) + .addTag("string") .build() - assertThat(feedbackProjectLogsItem).isNotNull + assertThat(feedbackProjectLogsItem.id()).isEqualTo("id") assertThat(feedbackProjectLogsItem.comment()).isEqualTo("comment") - assertThat(feedbackProjectLogsItem._expected()).isEqualTo(JsonNull.of()) + assertThat(feedbackProjectLogsItem._expected()) + .isEqualTo(JsonValue.from(mapOf())) assertThat(feedbackProjectLogsItem.metadata()) - .isEqualTo(FeedbackProjectLogsItem.Metadata.builder().build()) + .isEqualTo( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(feedbackProjectLogsItem.scores()) - .isEqualTo(FeedbackProjectLogsItem.Scores.builder().build()) + .isEqualTo( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) assertThat(feedbackProjectLogsItem.source()).isEqualTo(FeedbackProjectLogsItem.Source.APP) + assertThat(feedbackProjectLogsItem.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val feedbackProjectLogsItem = + FeedbackProjectLogsItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackProjectLogsItem.Source.APP) + .addTag("string") + .build() + + val roundtrippedFeedbackProjectLogsItem = + jsonMapper.readValue( + jsonMapper.writeValueAsString(feedbackProjectLogsItem), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFeedbackProjectLogsItem).isEqualTo(feedbackProjectLogsItem) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackResponseSchemaTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackResponseSchemaTest.kt index a1b62a0b..f7e73e95 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackResponseSchemaTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FeedbackResponseSchemaTest.kt @@ -2,16 +2,33 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FeedbackResponseSchemaTest { +internal class FeedbackResponseSchemaTest { @Test - fun createFeedbackResponseSchema() { + fun create() { val feedbackResponseSchema = FeedbackResponseSchema.builder().status(FeedbackResponseSchema.Status.SUCCESS).build() - assertThat(feedbackResponseSchema).isNotNull + assertThat(feedbackResponseSchema.status()).isEqualTo(FeedbackResponseSchema.Status.SUCCESS) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val feedbackResponseSchema = + FeedbackResponseSchema.builder().status(FeedbackResponseSchema.Status.SUCCESS).build() + + val roundtrippedFeedbackResponseSchema = + jsonMapper.readValue( + jsonMapper.writeValueAsString(feedbackResponseSchema), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFeedbackResponseSchema).isEqualTo(feedbackResponseSchema) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponseTest.kt index c3cee9b4..a575d143 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchDatasetEventsResponseTest.kt @@ -2,37 +2,47 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FetchDatasetEventsResponseTest { +internal class FetchDatasetEventsResponseTest { @Test - fun createFetchDatasetEventsResponse() { + fun create() { val fetchDatasetEventsResponse = FetchDatasetEventsResponse.builder() - .events( - listOf( - DatasetEvent.builder() - .id("id") - ._xactId("_xact_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .rootSpanId("root_span_id") - .spanId("span_id") - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(DatasetEvent.Metadata.builder().build()) - .tags(listOf("string")) - .build() - ) + .addEvent( + DatasetEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(DatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .addTag("string") + .build() ) .cursor("cursor") .build() - assertThat(fetchDatasetEventsResponse).isNotNull + assertThat(fetchDatasetEventsResponse.events()) .containsExactly( DatasetEvent.builder() @@ -43,12 +53,64 @@ class FetchDatasetEventsResponseTest { .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .rootSpanId("root_span_id") .spanId("span_id") - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(DatasetEvent.Metadata.builder().build()) - .tags(listOf("string")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(DatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .addTag("string") .build() ) assertThat(fetchDatasetEventsResponse.cursor()).isEqualTo("cursor") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val fetchDatasetEventsResponse = + FetchDatasetEventsResponse.builder() + .addEvent( + DatasetEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(DatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .addTag("string") + .build() + ) + .cursor("cursor") + .build() + + val roundtrippedFetchDatasetEventsResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(fetchDatasetEventsResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFetchDatasetEventsResponse).isEqualTo(fetchDatasetEventsResponse) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponseTest.kt index 1c2a5d72..0935bd19 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchExperimentEventsResponseTest.kt @@ -2,64 +2,77 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FetchExperimentEventsResponseTest { +internal class FetchExperimentEventsResponseTest { @Test - fun createFetchExperimentEventsResponse() { + fun create() { val fetchExperimentEventsResponse = FetchExperimentEventsResponse.builder() - .events( - listOf( - ExperimentEvent.builder() - .id("id") - ._xactId("_xact_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .rootSpanId("root_span_id") - .spanId("span_id") - .context( - ExperimentEvent.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(ExperimentEvent.Metadata.builder().build()) - .metrics( - ExperimentEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(ExperimentEvent.Scores.builder().build()) - .spanAttributes( - ExperimentEvent.SpanAttributes.builder() - .name("name") - .type(ExperimentEvent.SpanAttributes.Type.LLM) - .build() - ) - .spanParents(listOf("string")) - .tags(listOf("string")) - .build() - ) + .addEvent( + ExperimentEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .context( + ExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + ExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .addSpanParent("string") + .addTag("string") + .build() ) .cursor("cursor") .build() - assertThat(fetchExperimentEventsResponse).isNotNull + assertThat(fetchExperimentEventsResponse.events()) .containsExactly( ExperimentEvent.builder() @@ -74,35 +87,121 @@ class FetchExperimentEventsResponseTest { ExperimentEvent.Context.builder() .callerFilename("caller_filename") .callerFunctionname("caller_functionname") - .callerLineno(123L) + .callerLineno(0L) .build() ) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(ExperimentEvent.Metadata.builder().build()) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ExperimentEvent.Metadata.builder().model("model").build()) .metrics( ExperimentEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) .build() ) - .output(JsonNull.of()) - .scores(ExperimentEvent.Scores.builder().build()) - .spanAttributes( - ExperimentEvent.SpanAttributes.builder() - .name("name") - .type(ExperimentEvent.SpanAttributes.Type.LLM) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) .build() ) - .spanParents(listOf("string")) - .tags(listOf("string")) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .addSpanParent("string") + .addTag("string") .build() ) assertThat(fetchExperimentEventsResponse.cursor()).isEqualTo("cursor") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val fetchExperimentEventsResponse = + FetchExperimentEventsResponse.builder() + .addEvent( + ExperimentEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .context( + ExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + ExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .addSpanParent("string") + .addTag("string") + .build() + ) + .cursor("cursor") + .build() + + val roundtrippedFetchExperimentEventsResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(fetchExperimentEventsResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFetchExperimentEventsResponse) + .isEqualTo(fetchExperimentEventsResponse) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponseTest.kt index 9bf6fcbc..00ce083d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FetchProjectLogsEventsResponseTest.kt @@ -2,64 +2,78 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FetchProjectLogsEventsResponseTest { +internal class FetchProjectLogsEventsResponseTest { @Test - fun createFetchProjectLogsEventsResponse() { + fun create() { val fetchProjectLogsEventsResponse = FetchProjectLogsEventsResponse.builder() - .events( - listOf( - ProjectLogsEvent.builder() - .id("id") - ._xactId("_xact_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .logId(ProjectLogsEvent.LogId.G) - .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .rootSpanId("root_span_id") - .spanId("span_id") - .context( - ProjectLogsEvent.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(ProjectLogsEvent.Metadata.builder().build()) - .metrics( - ProjectLogsEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(ProjectLogsEvent.Scores.builder().build()) - .spanAttributes( - ProjectLogsEvent.SpanAttributes.builder() - .name("name") - .type(ProjectLogsEvent.SpanAttributes.Type.LLM) - .build() - ) - .spanParents(listOf("string")) - .tags(listOf("string")) - .build() - ) + .addEvent( + ProjectLogsEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .logId(ProjectLogsEvent.LogId.G) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .context( + ProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + ProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .addSpanParent("string") + .addTag("string") + .build() ) .cursor("cursor") .build() - assertThat(fetchProjectLogsEventsResponse).isNotNull + assertThat(fetchProjectLogsEventsResponse.events()) .containsExactly( ProjectLogsEvent.builder() @@ -75,34 +89,122 @@ class FetchProjectLogsEventsResponseTest { ProjectLogsEvent.Context.builder() .callerFilename("caller_filename") .callerFunctionname("caller_functionname") - .callerLineno(123L) + .callerLineno(0L) .build() ) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(ProjectLogsEvent.Metadata.builder().build()) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ProjectLogsEvent.Metadata.builder().model("model").build()) .metrics( ProjectLogsEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) .build() ) - .output(JsonNull.of()) - .scores(ProjectLogsEvent.Scores.builder().build()) - .spanAttributes( - ProjectLogsEvent.SpanAttributes.builder() - .name("name") - .type(ProjectLogsEvent.SpanAttributes.Type.LLM) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) .build() ) - .spanParents(listOf("string")) - .tags(listOf("string")) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .addSpanParent("string") + .addTag("string") .build() ) assertThat(fetchProjectLogsEventsResponse.cursor()).isEqualTo("cursor") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val fetchProjectLogsEventsResponse = + FetchProjectLogsEventsResponse.builder() + .addEvent( + ProjectLogsEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .logId(ProjectLogsEvent.LogId.G) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .context( + ProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + ProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .addSpanParent("string") + .addTag("string") + .build() + ) + .cursor("cursor") + .build() + + val roundtrippedFetchProjectLogsEventsResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(fetchProjectLogsEventsResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFetchProjectLogsEventsResponse) + .isEqualTo(fetchProjectLogsEventsResponse) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionCreateParamsTest.kt index c5cc94d4..18811155 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionCreateParamsTest.kt @@ -2,81 +2,81 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionCreateParamsTest { +internal class FunctionCreateParamsTest { @Test - fun createFunctionCreateParams() { + fun create() { FunctionCreateParams.builder() .functionData( - FunctionCreateParams.FunctionData.ofPrompt( - FunctionCreateParams.FunctionData.Prompt.builder() - .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionCreateParams.FunctionData.Prompt.builder() + .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionSchema( FunctionCreateParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) .functionType(FunctionCreateParams.FunctionType.LLM) .origin( FunctionCreateParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionCreateParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -90,105 +90,104 @@ class FunctionCreateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() } @Test - fun getBody() { + fun body() { val params = FunctionCreateParams.builder() .functionData( - FunctionCreateParams.FunctionData.ofPrompt( - FunctionCreateParams.FunctionData.Prompt.builder() - .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionCreateParams.FunctionData.Prompt.builder() + .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionSchema( FunctionCreateParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) .functionType(FunctionCreateParams.FunctionType.LLM) .origin( FunctionCreateParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionCreateParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -202,35 +201,34 @@ class FunctionCreateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.functionData()) .isEqualTo( FunctionCreateParams.FunctionData.ofPrompt( @@ -239,15 +237,15 @@ class FunctionCreateParamsTest { .build() ) ) - assertThat(body.name()).isEqualTo("name") + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") assertThat(body.functionSchema()) .isEqualTo( FunctionCreateParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) assertThat(body.functionType()).isEqualTo(FunctionCreateParams.FunctionType.LLM) @@ -255,7 +253,7 @@ class FunctionCreateParamsTest { .isEqualTo( FunctionCreateParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionCreateParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) @@ -263,43 +261,46 @@ class FunctionCreateParamsTest { .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -313,51 +314,48 @@ class FunctionCreateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - assertThat(body.tags()).isEqualTo(listOf("string")) + assertThat(body.tags()).containsExactly("string") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = FunctionCreateParams.builder() .functionData( - FunctionCreateParams.FunctionData.ofPrompt( - FunctionCreateParams.FunctionData.Prompt.builder() - .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionCreateParams.FunctionData.Prompt.builder() + .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.functionData()) .isEqualTo( FunctionCreateParams.FunctionData.ofPrompt( @@ -366,8 +364,8 @@ class FunctionCreateParamsTest { .build() ) ) - assertThat(body.name()).isEqualTo("name") + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionDeleteParamsTest.kt index b6a1f5f2..3e0df519 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionDeleteParamsTest.kt @@ -2,27 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionDeleteParamsTest { +internal class FunctionDeleteParamsTest { @Test - fun createFunctionDeleteParams() { + fun create() { FunctionDeleteParams.builder().functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = FunctionDeleteParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "functionId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionInvokeParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionInvokeParamsTest.kt index 8b261382..ffcd5df4 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionInvokeParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionInvokeParamsTest.kt @@ -2,32 +2,89 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionInvokeParamsTest { +internal class FunctionInvokeParamsTest { @Test - fun createFunctionInvokeParams() { + fun create() { FunctionInvokeParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .input(JsonNull.of()) - .messages( - listOf( - FunctionInvokeParams.Message.ofSystem( - FunctionInvokeParams.Message.System.builder() - .role(FunctionInvokeParams.Message.System.Role.SYSTEM) - .content("content") - .name("name") - .build() - ) - ) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .addMessage( + FunctionInvokeParams.Message.System.builder() + .role(FunctionInvokeParams.Message.System.Role.SYSTEM) + .content("content") + .name("name") + .build() + ) + .metadata( + FunctionInvokeParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() ) .mode(FunctionInvokeParams.Mode.AUTO) .parent( - FunctionInvokeParams.Parent.ofSpanParentStruct( + FunctionInvokeParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType( + FunctionInvokeParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS + ) + .propagatedEvent( + FunctionInvokeParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + FunctionInvokeParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() + ) + .stream(true) + .version("version") + .build() + } + + @Test + fun pathParams() { + val params = + FunctionInvokeParams.builder() + .functionId("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 body() { + val params = + FunctionInvokeParams.builder() + .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .addMessage( + FunctionInvokeParams.Message.System.builder() + .role(FunctionInvokeParams.Message.System.Role.SYSTEM) + .content("content") + .name("name") + .build() + ) + .metadata( + FunctionInvokeParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .mode(FunctionInvokeParams.Mode.AUTO) + .parent( FunctionInvokeParams.Parent.SpanParentStruct.builder() .objectId("object_id") .objectType( @@ -35,6 +92,7 @@ class FunctionInvokeParamsTest { ) .propagatedEvent( FunctionInvokeParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) .rowIds( @@ -46,70 +104,30 @@ class FunctionInvokeParamsTest { ) .build() ) - ) - .stream(true) - .version("version") - .build() - } - - @Test - fun getBody() { - val params = - FunctionInvokeParams.builder() - .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .input(JsonNull.of()) - .messages( - listOf( - FunctionInvokeParams.Message.ofSystem( - FunctionInvokeParams.Message.System.builder() - .role(FunctionInvokeParams.Message.System.Role.SYSTEM) - .content("content") - .name("name") - .build() - ) - ) - ) - .mode(FunctionInvokeParams.Mode.AUTO) - .parent( - FunctionInvokeParams.Parent.ofSpanParentStruct( - FunctionInvokeParams.Parent.SpanParentStruct.builder() - .objectId("object_id") - .objectType( - FunctionInvokeParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS - ) - .propagatedEvent( - FunctionInvokeParams.Parent.SpanParentStruct.PropagatedEvent - .builder() - .build() - ) - .rowIds( - FunctionInvokeParams.Parent.SpanParentStruct.RowIds.builder() - .id("id") - .rootSpanId("root_span_id") - .spanId("span_id") - .build() - ) - .build() - ) - ) .stream(true) .version("version") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.input()).isEqualTo(JsonNull.of()) + + val body = params._body() + + assertThat(body._expected()).isEqualTo(JsonValue.from(mapOf())) + assertThat(body._input()).isEqualTo(JsonValue.from(mapOf())) assertThat(body.messages()) - .isEqualTo( - listOf( - FunctionInvokeParams.Message.ofSystem( - FunctionInvokeParams.Message.System.builder() - .role(FunctionInvokeParams.Message.System.Role.SYSTEM) - .content("content") - .name("name") - .build() - ) + .containsExactly( + FunctionInvokeParams.Message.ofSystem( + FunctionInvokeParams.Message.System.builder() + .role(FunctionInvokeParams.Message.System.Role.SYSTEM) + .content("content") + .name("name") + .build() ) ) + assertThat(body.metadata()) + .isEqualTo( + FunctionInvokeParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(body.mode()).isEqualTo(FunctionInvokeParams.Mode.AUTO) assertThat(body.parent()) .isEqualTo( @@ -121,6 +139,7 @@ class FunctionInvokeParamsTest { ) .propagatedEvent( FunctionInvokeParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) .rowIds( @@ -138,25 +157,12 @@ class FunctionInvokeParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = FunctionInvokeParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - FunctionInvokeParams.builder() - .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "functionId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionInvokeResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionInvokeResponseTest.kt new file mode 100644 index 00000000..e1467ea3 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionInvokeResponseTest.kt @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.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 FunctionInvokeResponseTest { + + @Test + fun create() { + val functionInvokeResponse = FunctionInvokeResponse.builder().build() + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val functionInvokeResponse = FunctionInvokeResponse.builder().build() + + val roundtrippedFunctionInvokeResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(functionInvokeResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFunctionInvokeResponse).isEqualTo(functionInvokeResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionListPageResponseTest.kt new file mode 100644 index 00000000..f4021ef8 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionListPageResponseTest.kt @@ -0,0 +1,402 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class FunctionListPageResponseTest { + + @Test + fun create() { + val functionListPageResponse = + FunctionListPageResponse.builder() + .addObject( + Function.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .functionData( + Function.FunctionData.Prompt.builder() + .type(Function.FunctionData.Prompt.Type.PROMPT) + .build() + ) + .logId(Function.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionSchema( + Function.FunctionSchema.builder() + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) + .build() + ) + .functionType(Function.FunctionType.LLM) + .metadata( + Function.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .origin( + Function.Origin.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .internal_(true) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams + .FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams + .ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + .build() + + assertThat(functionListPageResponse.objects()) + .containsExactly( + Function.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .functionData( + Function.FunctionData.Prompt.builder() + .type(Function.FunctionData.Prompt.Type.PROMPT) + .build() + ) + .logId(Function.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionSchema( + Function.FunctionSchema.builder() + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) + .build() + ) + .functionType(Function.FunctionType.LLM) + .metadata( + Function.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .origin( + Function.Origin.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .internal_(true) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val functionListPageResponse = + FunctionListPageResponse.builder() + .addObject( + Function.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .functionData( + Function.FunctionData.Prompt.builder() + .type(Function.FunctionData.Prompt.Type.PROMPT) + .build() + ) + .logId(Function.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionSchema( + Function.FunctionSchema.builder() + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) + .build() + ) + .functionType(Function.FunctionType.LLM) + .metadata( + Function.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .origin( + Function.Origin.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .internal_(true) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams + .FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams + .ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + .build() + + val roundtrippedFunctionListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(functionListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedFunctionListPageResponse).isEqualTo(functionListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionListParamsTest.kt index 5e560da4..00e37ef9 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionListParamsTest.kt @@ -2,19 +2,19 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionListParamsTest { +internal class FunctionListParamsTest { @Test - fun createFunctionListParams() { + fun create() { FunctionListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .functionName("function_name") - .ids(FunctionListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") @@ -25,13 +25,13 @@ class FunctionListParamsTest { } @Test - fun getQueryParams() { + fun queryParams() { val params = FunctionListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .functionName("function_name") - .ids(FunctionListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") @@ -39,29 +39,32 @@ class FunctionListParamsTest { .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .version("version") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("function_name", listOf("function_name")) - expected.put( - "ids", - listOf( - FunctionListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("function_name", "function_name") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("project_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("project_name", "project_name") + .put("slug", "slug") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("version", "version") + .build() ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("project_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("project_name", listOf("project_name")) - expected.put("slug", listOf("slug")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("version", listOf("version")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = FunctionListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionReplaceParamsTest.kt index 3afb5a00..83335cde 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionReplaceParamsTest.kt @@ -2,81 +2,81 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionReplaceParamsTest { +internal class FunctionReplaceParamsTest { @Test - fun createFunctionReplaceParams() { + fun create() { FunctionReplaceParams.builder() .functionData( - FunctionReplaceParams.FunctionData.ofPrompt( - FunctionReplaceParams.FunctionData.Prompt.builder() - .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionReplaceParams.FunctionData.Prompt.builder() + .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionSchema( FunctionReplaceParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) .functionType(FunctionReplaceParams.FunctionType.LLM) .origin( FunctionReplaceParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionReplaceParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -90,105 +90,104 @@ class FunctionReplaceParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() } @Test - fun getBody() { + fun body() { val params = FunctionReplaceParams.builder() .functionData( - FunctionReplaceParams.FunctionData.ofPrompt( - FunctionReplaceParams.FunctionData.Prompt.builder() - .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionReplaceParams.FunctionData.Prompt.builder() + .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionSchema( FunctionReplaceParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) .functionType(FunctionReplaceParams.FunctionType.LLM) .origin( FunctionReplaceParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionReplaceParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -202,35 +201,34 @@ class FunctionReplaceParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.functionData()) .isEqualTo( FunctionReplaceParams.FunctionData.ofPrompt( @@ -239,15 +237,15 @@ class FunctionReplaceParamsTest { .build() ) ) - assertThat(body.name()).isEqualTo("name") + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") assertThat(body.functionSchema()) .isEqualTo( FunctionReplaceParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) assertThat(body.functionType()).isEqualTo(FunctionReplaceParams.FunctionType.LLM) @@ -255,7 +253,7 @@ class FunctionReplaceParamsTest { .isEqualTo( FunctionReplaceParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionReplaceParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) @@ -263,43 +261,46 @@ class FunctionReplaceParamsTest { .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -313,51 +314,48 @@ class FunctionReplaceParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - assertThat(body.tags()).isEqualTo(listOf("string")) + assertThat(body.tags()).containsExactly("string") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = FunctionReplaceParams.builder() .functionData( - FunctionReplaceParams.FunctionData.ofPrompt( - FunctionReplaceParams.FunctionData.Prompt.builder() - .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionReplaceParams.FunctionData.Prompt.builder() + .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.functionData()) .isEqualTo( FunctionReplaceParams.FunctionData.ofPrompt( @@ -366,8 +364,8 @@ class FunctionReplaceParamsTest { .build() ) ) - assertThat(body.name()).isEqualTo("name") + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionRetrieveParamsTest.kt index e67f96c5..fd70fae8 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionRetrieveParamsTest.kt @@ -2,27 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionRetrieveParamsTest { +internal class FunctionRetrieveParamsTest { @Test - fun createFunctionRetrieveParams() { + fun create() { FunctionRetrieveParams.builder().functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = FunctionRetrieveParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "functionId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionTest.kt index 80e13e97..3185de7d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionTest.kt @@ -2,25 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionTest { +internal class FunctionTest { @Test - fun createFunction() { + fun create() { val function = Function.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") ._xactId("_xact_id") .functionData( - Function.FunctionData.ofPrompt( - Function.FunctionData.Prompt.builder() - .type(Function.FunctionData.Prompt.Type.PROMPT) - .build() - ) + Function.FunctionData.Prompt.builder() + .type(Function.FunctionData.Prompt.Type.PROMPT) + .build() ) .logId(Function.LogId.P) .name("name") @@ -31,60 +31,67 @@ class FunctionTest { .description("description") .functionSchema( Function.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) .functionType(Function.FunctionType.LLM) - .metadata(Function.Metadata.builder().build()) + .metadata( + Function.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .origin( Function.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(Function.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -98,34 +105,32 @@ class FunctionTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() - assertThat(function).isNotNull + assertThat(function.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(function._xactId()).isEqualTo("_xact_id") assertThat(function.functionData()) @@ -146,17 +151,22 @@ class FunctionTest { assertThat(function.functionSchema()) .isEqualTo( Function.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) assertThat(function.functionType()).isEqualTo(Function.FunctionType.LLM) - assertThat(function.metadata()).isEqualTo(Function.Metadata.builder().build()) + assertThat(function.metadata()) + .isEqualTo( + Function.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(function.origin()) .isEqualTo( Function.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(Function.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) @@ -164,43 +174,46 @@ class FunctionTest { .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -214,31 +227,159 @@ class FunctionTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + assertThat(function.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val function = + Function.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .functionData( + Function.FunctionData.Prompt.builder() + .type(Function.FunctionData.Prompt.Type.PROMPT) + .build() + ) + .logId(Function.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionSchema( + Function.FunctionSchema.builder() + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) + .build() + ) + .functionType(Function.FunctionType.LLM) + .metadata( + Function.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .origin( + Function.Origin.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .internal_(true) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( PromptData.Prompt.Completion.builder() .content("content") .type(PromptData.Prompt.Completion.Type.COMPLETION) .build() ) - ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) - ) - .build() + .build() + ) + .addTag("string") + .build() + + val roundtrippedFunction = + jsonMapper.readValue( + jsonMapper.writeValueAsString(function), + jacksonTypeRef(), ) - assertThat(function.tags()).containsExactly("string") + + assertThat(roundtrippedFunction).isEqualTo(function) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionToolChoiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionToolChoiceTest.kt deleted file mode 100644 index 6321b346..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionToolChoiceTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class FunctionToolChoiceTest { - - @Test - fun createFunctionToolChoice() { - val functionToolChoice = FunctionToolChoice.builder().name("name").build() - assertThat(functionToolChoice).isNotNull - assertThat(functionToolChoice.name()).isEqualTo("name") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionUpdateParamsTest.kt index e5763185..3f9f9658 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/FunctionUpdateParamsTest.kt @@ -2,65 +2,66 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class FunctionUpdateParamsTest { +internal class FunctionUpdateParamsTest { @Test - fun createFunctionUpdateParams() { + fun create() { FunctionUpdateParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") .functionData( - FunctionUpdateParams.FunctionData.ofPrompt( - FunctionUpdateParams.FunctionData.Prompt.builder() - .type(FunctionUpdateParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionUpdateParams.FunctionData.Prompt.builder() + .type(FunctionUpdateParams.FunctionData.Prompt.Type.PROMPT) + .build() ) .name("name") .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -74,90 +75,101 @@ class FunctionUpdateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() } @Test - fun getBody() { + fun pathParams() { + val params = + FunctionUpdateParams.builder() + .functionId("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 body() { val params = FunctionUpdateParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") .functionData( - FunctionUpdateParams.FunctionData.ofPrompt( - FunctionUpdateParams.FunctionData.Prompt.builder() - .type(FunctionUpdateParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionUpdateParams.FunctionData.Prompt.builder() + .type(FunctionUpdateParams.FunctionData.Prompt.Type.PROMPT) + .build() ) .name("name") .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -171,35 +183,34 @@ class FunctionUpdateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.description()).isEqualTo("description") assertThat(body.functionData()) .isEqualTo( @@ -214,43 +225,46 @@ class FunctionUpdateParamsTest { .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -264,54 +278,39 @@ class FunctionUpdateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - assertThat(body.tags()).isEqualTo(listOf("string")) + assertThat(body.tags()).containsExactly("string") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = FunctionUpdateParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - FunctionUpdateParams.builder() - .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "functionId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupCreateParamsTest.kt index b7b98eb3..f6d24ec8 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupCreateParamsTest.kt @@ -2,47 +2,48 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class GroupCreateParamsTest { +internal class GroupCreateParamsTest { @Test - fun createGroupCreateParams() { + fun create() { GroupCreateParams.builder() - .name("name") + .name("x") .description("description") - .memberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .memberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() } @Test - fun getBody() { + fun body() { val params = GroupCreateParams.builder() - .name("name") + .name("x") .description("description") - .memberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .memberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") - assertThat(body.memberGroups()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(body.memberUsers()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + assertThat(body.memberGroups()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.memberUsers()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.orgName()).isEqualTo("org_name") } @Test - fun getBodyWithoutOptionalFields() { - val params = GroupCreateParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + fun bodyWithoutOptionalFields() { + val params = GroupCreateParams.builder().name("x").build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupDeleteParamsTest.kt index dd8a03f2..3f194aea 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupDeleteParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class GroupDeleteParamsTest { +internal class GroupDeleteParamsTest { @Test - fun createGroupDeleteParams() { + fun create() { GroupDeleteParams.builder().groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = GroupDeleteParams.builder().groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "groupId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupListPageResponseTest.kt new file mode 100644 index 00000000..136b59ee --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupListPageResponseTest.kt @@ -0,0 +1,76 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GroupListPageResponseTest { + + @Test + fun create() { + val groupListPageResponse = + GroupListPageResponse.builder() + .addObject( + Group.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(groupListPageResponse.objects()) + .containsExactly( + Group.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val groupListPageResponse = + GroupListPageResponse.builder() + .addObject( + Group.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedGroupListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(groupListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedGroupListPageResponse).isEqualTo(groupListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupListParamsTest.kt index 33587c15..17892a31 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupListParamsTest.kt @@ -2,52 +2,57 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class GroupListParamsTest { +internal class GroupListParamsTest { @Test - fun createGroupListParams() { + fun create() { GroupListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .groupName("group_name") - .ids(GroupListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = GroupListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .groupName("group_name") - .ids(GroupListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("group_name", listOf("group_name")) - expected.put( - "ids", - listOf(GroupListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("group_name", "group_name") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = GroupListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupReplaceParamsTest.kt index 4bc2570a..f6a474a7 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupReplaceParamsTest.kt @@ -2,47 +2,48 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class GroupReplaceParamsTest { +internal class GroupReplaceParamsTest { @Test - fun createGroupReplaceParams() { + fun create() { GroupReplaceParams.builder() - .name("name") + .name("x") .description("description") - .memberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .memberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() } @Test - fun getBody() { + fun body() { val params = GroupReplaceParams.builder() - .name("name") + .name("x") .description("description") - .memberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .memberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") - assertThat(body.memberGroups()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(body.memberUsers()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + assertThat(body.memberGroups()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.memberUsers()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.orgName()).isEqualTo("org_name") } @Test - fun getBodyWithoutOptionalFields() { - val params = GroupReplaceParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + fun bodyWithoutOptionalFields() { + val params = GroupReplaceParams.builder().name("x").build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupRetrieveParamsTest.kt index 40cb190f..88125d11 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupRetrieveParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class GroupRetrieveParamsTest { +internal class GroupRetrieveParamsTest { @Test - fun createGroupRetrieveParams() { + fun create() { GroupRetrieveParams.builder().groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = GroupRetrieveParams.builder().groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "groupId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupTest.kt index 6305f5e3..0c3d154f 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class GroupTest { +internal class GroupTest { @Test - fun createGroup() { + fun create() { val group = Group.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -18,11 +20,11 @@ class GroupTest { .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .description("description") - .memberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .memberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(group).isNotNull + assertThat(group.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(group.name()).isEqualTo("name") assertThat(group.orgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -33,4 +35,26 @@ class GroupTest { assertThat(group.memberUsers()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(group.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val group = + Group.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedGroup = + jsonMapper.readValue(jsonMapper.writeValueAsString(group), jacksonTypeRef()) + + assertThat(roundtrippedGroup).isEqualTo(group) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupUpdateParamsTest.kt index f84d7191..6f026692 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/GroupUpdateParamsTest.kt @@ -2,65 +2,63 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class GroupUpdateParamsTest { +internal class GroupUpdateParamsTest { @Test - fun createGroupUpdateParams() { + fun create() { GroupUpdateParams.builder() .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .addMemberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .addMemberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addAddMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addAddMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .name("name") - .removeMemberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .removeMemberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .name("x") + .addRemoveMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addRemoveMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getBody() { + fun pathParams() { + val params = + GroupUpdateParams.builder().groupId("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 body() { val params = GroupUpdateParams.builder() .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .addMemberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .addMemberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addAddMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addAddMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .name("name") - .removeMemberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .removeMemberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .name("x") + .addRemoveMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addRemoveMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.addMemberGroups()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(body.addMemberUsers()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + + val body = params._body() + + assertThat(body.addMemberGroups()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.addMemberUsers()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.description()).isEqualTo("description") - assertThat(body.name()).isEqualTo("name") + assertThat(body.name()).isEqualTo("x") assertThat(body.removeMemberGroups()) - .isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(body.removeMemberUsers()) - .isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.removeMemberUsers()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = GroupUpdateParams.builder().groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - GroupUpdateParams.builder().groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "groupId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventMergeTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventMergeTest.kt deleted file mode 100755 index 38cf160b..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventMergeTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.JsonNull -import java.time.OffsetDateTime -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class InsertDatasetEventMergeTest { - - @Test - fun createInsertDatasetEventMerge() { - val insertDatasetEventMerge = - InsertDatasetEventMerge.builder() - ._isMerge(true) - .id("id") - ._mergePaths(listOf(listOf("string"))) - ._objectDelete(true) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertDatasetEventMerge.Metadata.builder().build()) - .tags(listOf("string")) - .build() - assertThat(insertDatasetEventMerge).isNotNull - assertThat(insertDatasetEventMerge._isMerge()).isEqualTo(true) - assertThat(insertDatasetEventMerge.id()).isEqualTo("id") - assertThat(insertDatasetEventMerge._mergePaths()).containsExactly(listOf("string")) - assertThat(insertDatasetEventMerge._objectDelete()).isEqualTo(true) - assertThat(insertDatasetEventMerge.created()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(insertDatasetEventMerge._expected()).isEqualTo(JsonNull.of()) - assertThat(insertDatasetEventMerge._input()).isEqualTo(JsonNull.of()) - assertThat(insertDatasetEventMerge.metadata()) - .isEqualTo(InsertDatasetEventMerge.Metadata.builder().build()) - assertThat(insertDatasetEventMerge.tags()).containsExactly("string") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventReplaceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventReplaceTest.kt deleted file mode 100755 index 7ab922bf..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventReplaceTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.JsonNull -import java.time.OffsetDateTime -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class InsertDatasetEventReplaceTest { - - @Test - fun createInsertDatasetEventReplace() { - val insertDatasetEventReplace = - InsertDatasetEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertDatasetEventReplace.Metadata.builder().build()) - .tags(listOf("string")) - .build() - assertThat(insertDatasetEventReplace).isNotNull - assertThat(insertDatasetEventReplace.id()).isEqualTo("id") - assertThat(insertDatasetEventReplace._isMerge()).isEqualTo(true) - assertThat(insertDatasetEventReplace._objectDelete()).isEqualTo(true) - assertThat(insertDatasetEventReplace._parentId()).isEqualTo("_parent_id") - assertThat(insertDatasetEventReplace.created()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(insertDatasetEventReplace._expected()).isEqualTo(JsonNull.of()) - assertThat(insertDatasetEventReplace._input()).isEqualTo(JsonNull.of()) - assertThat(insertDatasetEventReplace.metadata()) - .isEqualTo(InsertDatasetEventReplace.Metadata.builder().build()) - assertThat(insertDatasetEventReplace.tags()).containsExactly("string") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventTest.kt new file mode 100644 index 00000000..10277cd5 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertDatasetEventTest.kt @@ -0,0 +1,106 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class InsertDatasetEventTest { + + @Test + fun create() { + val insertDatasetEvent = + InsertDatasetEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertDatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .rootSpanId("root_span_id") + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + + assertThat(insertDatasetEvent.id()).isEqualTo("id") + assertThat(insertDatasetEvent._isMerge()).isEqualTo(true) + assertThat(insertDatasetEvent._mergePaths()).containsExactly(listOf("string")) + assertThat(insertDatasetEvent._objectDelete()).isEqualTo(true) + assertThat(insertDatasetEvent._parentId()).isEqualTo("_parent_id") + assertThat(insertDatasetEvent.created()) + .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + assertThat(insertDatasetEvent._expected()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertDatasetEvent._input()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertDatasetEvent.metadata()) + .isEqualTo(InsertDatasetEvent.Metadata.builder().model("model").build()) + assertThat(insertDatasetEvent.origin()) + .isEqualTo( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + assertThat(insertDatasetEvent.rootSpanId()).isEqualTo("root_span_id") + assertThat(insertDatasetEvent.spanId()).isEqualTo("span_id") + assertThat(insertDatasetEvent.spanParents()).containsExactly("string") + assertThat(insertDatasetEvent.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val insertDatasetEvent = + InsertDatasetEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertDatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .rootSpanId("root_span_id") + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + + val roundtrippedInsertDatasetEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(insertDatasetEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedInsertDatasetEvent).isEqualTo(insertDatasetEvent) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertEventsResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertEventsResponseTest.kt index a55a1208..560e7fd1 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertEventsResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertEventsResponseTest.kt @@ -2,15 +2,31 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class InsertEventsResponseTest { +internal class InsertEventsResponseTest { @Test - fun createInsertEventsResponse() { - val insertEventsResponse = InsertEventsResponse.builder().rowIds(listOf("string")).build() - assertThat(insertEventsResponse).isNotNull + fun create() { + val insertEventsResponse = InsertEventsResponse.builder().addRowId("string").build() + assertThat(insertEventsResponse.rowIds()).containsExactly("string") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val insertEventsResponse = InsertEventsResponse.builder().addRowId("string").build() + + val roundtrippedInsertEventsResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(insertEventsResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedInsertEventsResponse).isEqualTo(insertEventsResponse) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventMergeTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventMergeTest.kt deleted file mode 100755 index 4d793528..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventMergeTest.kt +++ /dev/null @@ -1,95 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.JsonNull -import java.time.OffsetDateTime -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class InsertExperimentEventMergeTest { - - @Test - fun createInsertExperimentEventMerge() { - val insertExperimentEventMerge = - InsertExperimentEventMerge.builder() - ._isMerge(true) - .id("id") - ._mergePaths(listOf(listOf("string"))) - ._objectDelete(true) - .context( - InsertExperimentEventMerge.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertExperimentEventMerge.Metadata.builder().build()) - .metrics( - InsertExperimentEventMerge.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertExperimentEventMerge.Scores.builder().build()) - .spanAttributes( - InsertExperimentEventMerge.SpanAttributes.builder() - .name("name") - .type(InsertExperimentEventMerge.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - assertThat(insertExperimentEventMerge).isNotNull - assertThat(insertExperimentEventMerge._isMerge()).isEqualTo(true) - assertThat(insertExperimentEventMerge.id()).isEqualTo("id") - assertThat(insertExperimentEventMerge._mergePaths()).containsExactly(listOf("string")) - assertThat(insertExperimentEventMerge._objectDelete()).isEqualTo(true) - assertThat(insertExperimentEventMerge.context()) - .isEqualTo( - InsertExperimentEventMerge.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - assertThat(insertExperimentEventMerge.created()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(insertExperimentEventMerge.datasetRecordId()).isEqualTo("dataset_record_id") - assertThat(insertExperimentEventMerge._error()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventMerge._expected()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventMerge._input()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventMerge.metadata()) - .isEqualTo(InsertExperimentEventMerge.Metadata.builder().build()) - assertThat(insertExperimentEventMerge.metrics()) - .isEqualTo( - InsertExperimentEventMerge.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - assertThat(insertExperimentEventMerge._output()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventMerge.scores()) - .isEqualTo(InsertExperimentEventMerge.Scores.builder().build()) - assertThat(insertExperimentEventMerge.spanAttributes()) - .isEqualTo( - InsertExperimentEventMerge.SpanAttributes.builder() - .name("name") - .type(InsertExperimentEventMerge.SpanAttributes.Type.LLM) - .build() - ) - assertThat(insertExperimentEventMerge.tags()).containsExactly("string") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventReplaceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventReplaceTest.kt deleted file mode 100755 index 6b688152..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventReplaceTest.kt +++ /dev/null @@ -1,95 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.JsonNull -import java.time.OffsetDateTime -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class InsertExperimentEventReplaceTest { - - @Test - fun createInsertExperimentEventReplace() { - val insertExperimentEventReplace = - InsertExperimentEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertExperimentEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertExperimentEventReplace.Metadata.builder().build()) - .metrics( - InsertExperimentEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertExperimentEventReplace.Scores.builder().build()) - .spanAttributes( - InsertExperimentEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertExperimentEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - assertThat(insertExperimentEventReplace).isNotNull - assertThat(insertExperimentEventReplace.id()).isEqualTo("id") - assertThat(insertExperimentEventReplace._isMerge()).isEqualTo(true) - assertThat(insertExperimentEventReplace._objectDelete()).isEqualTo(true) - assertThat(insertExperimentEventReplace._parentId()).isEqualTo("_parent_id") - assertThat(insertExperimentEventReplace.context()) - .isEqualTo( - InsertExperimentEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - assertThat(insertExperimentEventReplace.created()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(insertExperimentEventReplace.datasetRecordId()).isEqualTo("dataset_record_id") - assertThat(insertExperimentEventReplace._error()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventReplace._expected()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventReplace._input()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventReplace.metadata()) - .isEqualTo(InsertExperimentEventReplace.Metadata.builder().build()) - assertThat(insertExperimentEventReplace.metrics()) - .isEqualTo( - InsertExperimentEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - assertThat(insertExperimentEventReplace._output()).isEqualTo(JsonNull.of()) - assertThat(insertExperimentEventReplace.scores()) - .isEqualTo(InsertExperimentEventReplace.Scores.builder().build()) - assertThat(insertExperimentEventReplace.spanAttributes()) - .isEqualTo( - InsertExperimentEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertExperimentEventReplace.SpanAttributes.Type.LLM) - .build() - ) - assertThat(insertExperimentEventReplace.tags()).containsExactly("string") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventTest.kt new file mode 100644 index 00000000..85c3a375 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertExperimentEventTest.kt @@ -0,0 +1,192 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class InsertExperimentEventTest { + + @Test + fun create() { + val insertExperimentEvent = + InsertExperimentEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + + assertThat(insertExperimentEvent.id()).isEqualTo("id") + assertThat(insertExperimentEvent._isMerge()).isEqualTo(true) + assertThat(insertExperimentEvent._mergePaths()).containsExactly(listOf("string")) + assertThat(insertExperimentEvent._objectDelete()).isEqualTo(true) + assertThat(insertExperimentEvent._parentId()).isEqualTo("_parent_id") + assertThat(insertExperimentEvent.context()) + .isEqualTo( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + assertThat(insertExperimentEvent.created()) + .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + assertThat(insertExperimentEvent._error()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertExperimentEvent._expected()) + .isEqualTo(JsonValue.from(mapOf())) + assertThat(insertExperimentEvent._input()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertExperimentEvent.metadata()) + .isEqualTo(InsertExperimentEvent.Metadata.builder().model("model").build()) + assertThat(insertExperimentEvent.metrics()) + .isEqualTo( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + assertThat(insertExperimentEvent.origin()) + .isEqualTo( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + assertThat(insertExperimentEvent._output()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertExperimentEvent.rootSpanId()).isEqualTo("root_span_id") + assertThat(insertExperimentEvent.scores()) + .isEqualTo( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + assertThat(insertExperimentEvent.spanAttributes()) + .isEqualTo(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + assertThat(insertExperimentEvent.spanId()).isEqualTo("span_id") + assertThat(insertExperimentEvent.spanParents()).containsExactly("string") + assertThat(insertExperimentEvent.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val insertExperimentEvent = + InsertExperimentEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertExperimentEvent.Metadata.builder().model("model").build()) + .metrics( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + + val roundtrippedInsertExperimentEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(insertExperimentEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedInsertExperimentEvent).isEqualTo(insertExperimentEvent) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventMergeTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventMergeTest.kt deleted file mode 100755 index 6567fef7..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventMergeTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.JsonNull -import java.time.OffsetDateTime -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class InsertProjectLogsEventMergeTest { - - @Test - fun createInsertProjectLogsEventMerge() { - val insertProjectLogsEventMerge = - InsertProjectLogsEventMerge.builder() - ._isMerge(true) - .id("id") - ._mergePaths(listOf(listOf("string"))) - ._objectDelete(true) - .context( - InsertProjectLogsEventMerge.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertProjectLogsEventMerge.Metadata.builder().build()) - .metrics( - InsertProjectLogsEventMerge.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertProjectLogsEventMerge.Scores.builder().build()) - .spanAttributes( - InsertProjectLogsEventMerge.SpanAttributes.builder() - .name("name") - .type(InsertProjectLogsEventMerge.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - assertThat(insertProjectLogsEventMerge).isNotNull - assertThat(insertProjectLogsEventMerge._isMerge()).isEqualTo(true) - assertThat(insertProjectLogsEventMerge.id()).isEqualTo("id") - assertThat(insertProjectLogsEventMerge._mergePaths()).containsExactly(listOf("string")) - assertThat(insertProjectLogsEventMerge._objectDelete()).isEqualTo(true) - assertThat(insertProjectLogsEventMerge.context()) - .isEqualTo( - InsertProjectLogsEventMerge.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - assertThat(insertProjectLogsEventMerge.created()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(insertProjectLogsEventMerge._error()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventMerge._expected()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventMerge._input()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventMerge.metadata()) - .isEqualTo(InsertProjectLogsEventMerge.Metadata.builder().build()) - assertThat(insertProjectLogsEventMerge.metrics()) - .isEqualTo( - InsertProjectLogsEventMerge.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - assertThat(insertProjectLogsEventMerge._output()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventMerge.scores()) - .isEqualTo(InsertProjectLogsEventMerge.Scores.builder().build()) - assertThat(insertProjectLogsEventMerge.spanAttributes()) - .isEqualTo( - InsertProjectLogsEventMerge.SpanAttributes.builder() - .name("name") - .type(InsertProjectLogsEventMerge.SpanAttributes.Type.LLM) - .build() - ) - assertThat(insertProjectLogsEventMerge.tags()).containsExactly("string") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventReplaceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventReplaceTest.kt deleted file mode 100755 index 35d49733..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventReplaceTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.JsonNull -import java.time.OffsetDateTime -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class InsertProjectLogsEventReplaceTest { - - @Test - fun createInsertProjectLogsEventReplace() { - val insertProjectLogsEventReplace = - InsertProjectLogsEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertProjectLogsEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertProjectLogsEventReplace.Metadata.builder().build()) - .metrics( - InsertProjectLogsEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertProjectLogsEventReplace.Scores.builder().build()) - .spanAttributes( - InsertProjectLogsEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertProjectLogsEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - assertThat(insertProjectLogsEventReplace).isNotNull - assertThat(insertProjectLogsEventReplace.id()).isEqualTo("id") - assertThat(insertProjectLogsEventReplace._isMerge()).isEqualTo(true) - assertThat(insertProjectLogsEventReplace._objectDelete()).isEqualTo(true) - assertThat(insertProjectLogsEventReplace._parentId()).isEqualTo("_parent_id") - assertThat(insertProjectLogsEventReplace.context()) - .isEqualTo( - InsertProjectLogsEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - assertThat(insertProjectLogsEventReplace.created()) - .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - assertThat(insertProjectLogsEventReplace._error()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventReplace._expected()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventReplace._input()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventReplace.metadata()) - .isEqualTo(InsertProjectLogsEventReplace.Metadata.builder().build()) - assertThat(insertProjectLogsEventReplace.metrics()) - .isEqualTo( - InsertProjectLogsEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - assertThat(insertProjectLogsEventReplace._output()).isEqualTo(JsonNull.of()) - assertThat(insertProjectLogsEventReplace.scores()) - .isEqualTo(InsertProjectLogsEventReplace.Scores.builder().build()) - assertThat(insertProjectLogsEventReplace.spanAttributes()) - .isEqualTo( - InsertProjectLogsEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertProjectLogsEventReplace.SpanAttributes.Type.LLM) - .build() - ) - assertThat(insertProjectLogsEventReplace.tags()).containsExactly("string") - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventTest.kt new file mode 100644 index 00000000..74b21128 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/InsertProjectLogsEventTest.kt @@ -0,0 +1,192 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class InsertProjectLogsEventTest { + + @Test + fun create() { + val insertProjectLogsEvent = + InsertProjectLogsEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + + assertThat(insertProjectLogsEvent.id()).isEqualTo("id") + assertThat(insertProjectLogsEvent._isMerge()).isEqualTo(true) + assertThat(insertProjectLogsEvent._mergePaths()).containsExactly(listOf("string")) + assertThat(insertProjectLogsEvent._objectDelete()).isEqualTo(true) + assertThat(insertProjectLogsEvent._parentId()).isEqualTo("_parent_id") + assertThat(insertProjectLogsEvent.context()) + .isEqualTo( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + assertThat(insertProjectLogsEvent.created()) + .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + assertThat(insertProjectLogsEvent._error()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertProjectLogsEvent._expected()) + .isEqualTo(JsonValue.from(mapOf())) + assertThat(insertProjectLogsEvent._input()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertProjectLogsEvent.metadata()) + .isEqualTo(InsertProjectLogsEvent.Metadata.builder().model("model").build()) + assertThat(insertProjectLogsEvent.metrics()) + .isEqualTo( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + assertThat(insertProjectLogsEvent.origin()) + .isEqualTo( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + assertThat(insertProjectLogsEvent._output()).isEqualTo(JsonValue.from(mapOf())) + assertThat(insertProjectLogsEvent.rootSpanId()).isEqualTo("root_span_id") + assertThat(insertProjectLogsEvent.scores()) + .isEqualTo( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + assertThat(insertProjectLogsEvent.spanAttributes()) + .isEqualTo(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + assertThat(insertProjectLogsEvent.spanId()).isEqualTo("span_id") + assertThat(insertProjectLogsEvent.spanParents()).containsExactly("string") + assertThat(insertProjectLogsEvent.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val insertProjectLogsEvent = + InsertProjectLogsEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + + val roundtrippedInsertProjectLogsEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(insertProjectLogsEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedInsertProjectLogsEvent).isEqualTo(insertProjectLogsEvent) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/MetricSummaryTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/MetricSummaryTest.kt index 028cc804..d947a3ed 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/MetricSummaryTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/MetricSummaryTest.kt @@ -2,28 +2,52 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class MetricSummaryTest { +internal class MetricSummaryTest { @Test - fun createMetricSummary() { + fun create() { val metricSummary = MetricSummary.builder() - .improvements(123L) - .metric(42.23) + .improvements(0L) + .metric(0.0) .name("name") - .regressions(123L) + .regressions(0L) .unit("unit") - .diff(42.23) + .diff(0.0) .build() - assertThat(metricSummary).isNotNull - assertThat(metricSummary.improvements()).isEqualTo(123L) - assertThat(metricSummary.metric()).isEqualTo(42.23) + + assertThat(metricSummary.improvements()).isEqualTo(0L) + assertThat(metricSummary.metric()).isEqualTo(0.0) assertThat(metricSummary.name()).isEqualTo("name") - assertThat(metricSummary.regressions()).isEqualTo(123L) + assertThat(metricSummary.regressions()).isEqualTo(0L) assertThat(metricSummary.unit()).isEqualTo("unit") - assertThat(metricSummary.diff()).isEqualTo(42.23) + assertThat(metricSummary.diff()).isEqualTo(0.0) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val metricSummary = + MetricSummary.builder() + .improvements(0L) + .metric(0.0) + .name("name") + .regressions(0L) + .unit("unit") + .diff(0.0) + .build() + + val roundtrippedMetricSummary = + jsonMapper.readValue( + jsonMapper.writeValueAsString(metricSummary), + jacksonTypeRef(), + ) + + assertThat(roundtrippedMetricSummary).isEqualTo(metricSummary) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ObjectReferenceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ObjectReferenceTest.kt new file mode 100644 index 00000000..f21fac5d --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ObjectReferenceTest.kt @@ -0,0 +1,50 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.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 ObjectReferenceTest { + + @Test + fun create() { + val objectReference = + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + + assertThat(objectReference.id()).isEqualTo("id") + assertThat(objectReference._xactId()).isEqualTo("_xact_id") + assertThat(objectReference.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(objectReference.objectType()).isEqualTo(ObjectReference.ObjectType.EXPERIMENT) + assertThat(objectReference.created()).isEqualTo("created") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val objectReference = + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + + val roundtrippedObjectReference = + jsonMapper.readValue( + jsonMapper.writeValueAsString(objectReference), + jacksonTypeRef(), + ) + + assertThat(roundtrippedObjectReference).isEqualTo(objectReference) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OnlineScoreConfigTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OnlineScoreConfigTest.kt index 948af8bd..0deeffca 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OnlineScoreConfigTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OnlineScoreConfigTest.kt @@ -2,31 +2,29 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class OnlineScoreConfigTest { +internal class OnlineScoreConfigTest { @Test - fun createOnlineScoreConfig() { + fun create() { val onlineScoreConfig = OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() - assertThat(onlineScoreConfig).isNotNull - assertThat(onlineScoreConfig.samplingRate()).isEqualTo(1.0) + + assertThat(onlineScoreConfig.samplingRate()).isEqualTo(0.0) assertThat(onlineScoreConfig.scorers()) .containsExactly( OnlineScoreConfig.Scorer.ofFunction( @@ -39,4 +37,29 @@ class OnlineScoreConfigTest { assertThat(onlineScoreConfig.applyToRootSpan()).isEqualTo(true) assertThat(onlineScoreConfig.applyToSpanNames()).containsExactly("string") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val onlineScoreConfig = + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + + val roundtrippedOnlineScoreConfig = + jsonMapper.readValue( + jsonMapper.writeValueAsString(onlineScoreConfig), + jacksonTypeRef(), + ) + + assertThat(roundtrippedOnlineScoreConfig).isEqualTo(onlineScoreConfig) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationDeleteParamsTest.kt index 1c6fe6ac..365faa22 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationDeleteParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class OrganizationDeleteParamsTest { +internal class OrganizationDeleteParamsTest { @Test - fun createOrganizationDeleteParams() { + fun create() { OrganizationDeleteParams.builder() .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = OrganizationDeleteParams.builder() .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "organizationId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationListPageResponseTest.kt new file mode 100644 index 00000000..a425684a --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationListPageResponseTest.kt @@ -0,0 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class OrganizationListPageResponseTest { + + @Test + fun create() { + val organizationListPageResponse = + OrganizationListPageResponse.builder() + .addObject( + Organization.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .apiUrl("api_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .isUniversalApi(true) + .proxyUrl("proxy_url") + .realtimeUrl("realtime_url") + .build() + ) + .build() + + assertThat(organizationListPageResponse.objects()) + .containsExactly( + Organization.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .apiUrl("api_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .isUniversalApi(true) + .proxyUrl("proxy_url") + .realtimeUrl("realtime_url") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val organizationListPageResponse = + OrganizationListPageResponse.builder() + .addObject( + Organization.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .apiUrl("api_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .isUniversalApi(true) + .proxyUrl("proxy_url") + .realtimeUrl("realtime_url") + .build() + ) + .build() + + val roundtrippedOrganizationListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(organizationListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedOrganizationListPageResponse).isEqualTo(organizationListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationListParamsTest.kt index 59b904b0..32cdfdf6 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationListParamsTest.kt @@ -2,52 +2,54 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class OrganizationListParamsTest { +internal class OrganizationListParamsTest { @Test - fun createOrganizationListParams() { + fun create() { OrganizationListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(OrganizationListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = OrganizationListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(OrganizationListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf( - OrganizationListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = OrganizationListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParamsTest.kt index 99b5aca9..6c4a077c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationMemberUpdateParamsTest.kt @@ -2,23 +2,22 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class OrganizationMemberUpdateParamsTest { +internal class OrganizationMemberUpdateParamsTest { @Test - fun createOrganizationMemberUpdateParams() { + fun create() { OrganizationMemberUpdateParams.builder() .inviteUsers( OrganizationMemberUpdateParams.InviteUsers.builder() - .emails(listOf("string")) + .addEmail("string") .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .groupIds(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .groupName("group_name") - .groupNames(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupName("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .sendInviteEmails(true) .build() ) @@ -26,25 +25,25 @@ class OrganizationMemberUpdateParamsTest { .orgName("org_name") .removeUsers( OrganizationMemberUpdateParams.RemoveUsers.builder() - .emails(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addEmail("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) .build() } @Test - fun getBody() { + fun body() { val params = OrganizationMemberUpdateParams.builder() .inviteUsers( OrganizationMemberUpdateParams.InviteUsers.builder() - .emails(listOf("string")) + .addEmail("string") .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .groupIds(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .groupName("group_name") - .groupNames(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupName("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .sendInviteEmails(true) .build() ) @@ -52,22 +51,23 @@ class OrganizationMemberUpdateParamsTest { .orgName("org_name") .removeUsers( OrganizationMemberUpdateParams.RemoveUsers.builder() - .emails(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addEmail("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.inviteUsers()) .isEqualTo( OrganizationMemberUpdateParams.InviteUsers.builder() - .emails(listOf("string")) + .addEmail("string") .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .groupIds(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .groupName("group_name") - .groupNames(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupName("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .sendInviteEmails(true) .build() ) @@ -76,16 +76,16 @@ class OrganizationMemberUpdateParamsTest { assertThat(body.removeUsers()) .isEqualTo( OrganizationMemberUpdateParams.RemoveUsers.builder() - .emails(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addEmail("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = OrganizationMemberUpdateParams.builder().build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParamsTest.kt index 4ccbda0e..bb59a8e4 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationRetrieveParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class OrganizationRetrieveParamsTest { +internal class OrganizationRetrieveParamsTest { @Test - fun createOrganizationRetrieveParams() { + fun create() { OrganizationRetrieveParams.builder() .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = OrganizationRetrieveParams.builder() .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "organizationId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationTest.kt index 5296d7d8..d4dbfc4a 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class OrganizationTest { +internal class OrganizationTest { @Test - fun createOrganization() { + fun create() { val organization = Organization.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -20,7 +22,7 @@ class OrganizationTest { .proxyUrl("proxy_url") .realtimeUrl("realtime_url") .build() - assertThat(organization).isNotNull + assertThat(organization.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(organization.name()).isEqualTo("name") assertThat(organization.apiUrl()).isEqualTo("api_url") @@ -30,4 +32,27 @@ class OrganizationTest { assertThat(organization.proxyUrl()).isEqualTo("proxy_url") assertThat(organization.realtimeUrl()).isEqualTo("realtime_url") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val organization = + Organization.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .apiUrl("api_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .isUniversalApi(true) + .proxyUrl("proxy_url") + .realtimeUrl("realtime_url") + .build() + + val roundtrippedOrganization = + jsonMapper.readValue( + jsonMapper.writeValueAsString(organization), + jacksonTypeRef(), + ) + + assertThat(roundtrippedOrganization).isEqualTo(organization) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationUpdateParamsTest.kt index cc38ee32..c094dd4c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/OrganizationUpdateParamsTest.kt @@ -2,14 +2,13 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class OrganizationUpdateParamsTest { +internal class OrganizationUpdateParamsTest { @Test - fun createOrganizationUpdateParams() { + fun create() { OrganizationUpdateParams.builder() .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .apiUrl("api_url") @@ -21,7 +20,19 @@ class OrganizationUpdateParamsTest { } @Test - fun getBody() { + fun pathParams() { + val params = + OrganizationUpdateParams.builder() + .organizationId("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 body() { val params = OrganizationUpdateParams.builder() .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -31,8 +42,9 @@ class OrganizationUpdateParamsTest { .proxyUrl("proxy_url") .realtimeUrl("realtime_url") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.apiUrl()).isEqualTo("api_url") assertThat(body.isUniversalApi()).isEqualTo(true) assertThat(body.name()).isEqualTo("name") @@ -41,25 +53,12 @@ class OrganizationUpdateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = OrganizationUpdateParams.builder() .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - OrganizationUpdateParams.builder() - .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "organizationId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutputTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutputTest.kt index 2d2ed4ea..5b5b45b3 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutputTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PatchOrganizationMembersOutputTest.kt @@ -2,21 +2,45 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PatchOrganizationMembersOutputTest { +internal class PatchOrganizationMembersOutputTest { @Test - fun createPatchOrganizationMembersOutput() { + fun create() { val patchOrganizationMembersOutput = PatchOrganizationMembersOutput.builder() + .orgId("org_id") .status(PatchOrganizationMembersOutput.Status.SUCCESS) .sendEmailError("send_email_error") .build() - assertThat(patchOrganizationMembersOutput).isNotNull + + assertThat(patchOrganizationMembersOutput.orgId()).isEqualTo("org_id") assertThat(patchOrganizationMembersOutput.status()) .isEqualTo(PatchOrganizationMembersOutput.Status.SUCCESS) assertThat(patchOrganizationMembersOutput.sendEmailError()).isEqualTo("send_email_error") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val patchOrganizationMembersOutput = + PatchOrganizationMembersOutput.builder() + .orgId("org_id") + .status(PatchOrganizationMembersOutput.Status.SUCCESS) + .sendEmailError("send_email_error") + .build() + + val roundtrippedPatchOrganizationMembersOutput = + jsonMapper.readValue( + jsonMapper.writeValueAsString(patchOrganizationMembersOutput), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPatchOrganizationMembersOutput) + .isEqualTo(patchOrganizationMembersOutput) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PathLookupFilterTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PathLookupFilterTest.kt deleted file mode 100755 index 4d32afc1..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PathLookupFilterTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import com.braintrustdata.api.core.JsonNull -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class PathLookupFilterTest { - - @Test - fun createPathLookupFilter() { - val pathLookupFilter = - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - assertThat(pathLookupFilter).isNotNull - assertThat(pathLookupFilter.path()).containsExactly("string") - assertThat(pathLookupFilter.type()).isEqualTo(PathLookupFilter.Type.PATH_LOOKUP) - assertThat(pathLookupFilter._value()).isEqualTo(JsonNull.of()) - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectCreateParamsTest.kt index 10928d7b..de237c19 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectCreateParamsTest.kt @@ -2,31 +2,32 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectCreateParamsTest { +internal class ProjectCreateParamsTest { @Test - fun createProjectCreateParams() { - ProjectCreateParams.builder().name("name").orgName("org_name").build() + fun create() { + ProjectCreateParams.builder().name("x").orgName("org_name").build() } @Test - fun getBody() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + fun body() { + val params = ProjectCreateParams.builder().name("x").orgName("org_name").build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.orgName()).isEqualTo("org_name") } @Test - fun getBodyWithoutOptionalFields() { - val params = ProjectCreateParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + fun bodyWithoutOptionalFields() { + val params = ProjectCreateParams.builder().name("x").build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectDeleteParamsTest.kt index caa2ac8b..47a71480 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectDeleteParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectDeleteParamsTest { +internal class ProjectDeleteParamsTest { @Test - fun createProjectDeleteParams() { + fun create() { ProjectDeleteParams.builder().projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = ProjectDeleteParams.builder().projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "projectId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectListPageResponseTest.kt new file mode 100644 index 00000000..1e9fdd55 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectListPageResponseTest.kt @@ -0,0 +1,109 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ProjectListPageResponseTest { + + @Test + fun create() { + val projectListPageResponse = + ProjectListPageResponse.builder() + .addObject( + Project.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(projectListPageResponse.objects()) + .containsExactly( + Project.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectListPageResponse = + ProjectListPageResponse.builder() + .addObject( + Project.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedProjectListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectListPageResponse).isEqualTo(projectListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectListParamsTest.kt index 233ceaa7..9f6452cd 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectListParamsTest.kt @@ -2,18 +2,18 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectListParamsTest { +internal class ProjectListParamsTest { @Test - fun createProjectListParams() { + fun create() { ProjectListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ProjectListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectName("project_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -21,35 +21,38 @@ class ProjectListParamsTest { } @Test - fun getQueryParams() { + fun queryParams() { val params = ProjectListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ProjectListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectName("project_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf( - ProjectListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("project_name", "project_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("project_name", listOf("project_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = ProjectListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParamsTest.kt index c2b19357..59f797ac 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFeedbackParamsTest.kt @@ -2,91 +2,112 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectLogFeedbackParamsTest { +internal class ProjectLogFeedbackParamsTest { @Test - fun createProjectLogFeedbackParams() { + fun create() { ProjectLogFeedbackParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackProjectLogsItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackProjectLogsItem.Metadata.builder().build()) - .scores(FeedbackProjectLogsItem.Scores.builder().build()) - .source(FeedbackProjectLogsItem.Source.APP) - .build() - ) + .addFeedback( + FeedbackProjectLogsItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackProjectLogsItem.Source.APP) + .addTag("string") + .build() ) .build() } @Test - fun getBody() { + fun pathParams() { val params = ProjectLogFeedbackParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackProjectLogsItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackProjectLogsItem.Metadata.builder().build()) - .scores(FeedbackProjectLogsItem.Scores.builder().build()) - .source(FeedbackProjectLogsItem.Source.APP) - .build() - ) - ) + .addFeedback(FeedbackProjectLogsItem.builder().id("id").build()) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.feedback()) - .isEqualTo( - listOf( - FeedbackProjectLogsItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackProjectLogsItem.Metadata.builder().build()) - .scores(FeedbackProjectLogsItem.Scores.builder().build()) - .source(FeedbackProjectLogsItem.Source.APP) - .build() - ) - ) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = ProjectLogFeedbackParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback(listOf(FeedbackProjectLogsItem.builder().id("id").build())) + .addFeedback( + FeedbackProjectLogsItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackProjectLogsItem.Source.APP) + .addTag("string") + .build() + ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.feedback()) - .isEqualTo(listOf(FeedbackProjectLogsItem.builder().id("id").build())) + .containsExactly( + FeedbackProjectLogsItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackProjectLogsItem.Source.APP) + .addTag("string") + .build() + ) } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = ProjectLogFeedbackParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback(listOf(FeedbackProjectLogsItem.builder().id("id").build())) + .addFeedback(FeedbackProjectLogsItem.builder().id("id").build()) .build() - assertThat(params).isNotNull - // path param "projectId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.feedback()) + .containsExactly(FeedbackProjectLogsItem.builder().id("id").build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchParamsTest.kt index c84026c0..545e215e 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchParamsTest.kt @@ -2,17 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectLogFetchParamsTest { +internal class ProjectLogFetchParamsTest { @Test - fun createProjectLogFetchParams() { + fun create() { ProjectLogFetchParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") @@ -20,43 +20,50 @@ class ProjectLogFetchParamsTest { } @Test - fun getQueryParams() { + fun pathParams() { val params = ProjectLogFetchParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) - .maxRootSpanId("max_root_span_id") - .maxXactId("max_xact_id") - .version("version") .build() - val expected = mutableMapOf>() - expected.put("limit", listOf("123")) - expected.put("max_root_span_id", listOf("max_root_span_id")) - expected.put("max_xact_id", listOf("max_xact_id")) - expected.put("version", listOf("version")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParams() { val params = ProjectLogFetchParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") .build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("limit", "0") + .put("max_root_span_id", "max_root_span_id") + .put("max_xact_id", "max_xact_id") + .put("version", "version") + .build() + ) } @Test - fun getPathParam() { + fun queryParamsWithoutOptionalFields() { val params = ProjectLogFetchParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "projectId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParamsTest.kt index acb4cc3d..393beb83 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogFetchPostParamsTest.kt @@ -2,28 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectLogFetchPostParamsTest { +internal class ProjectLogFetchPostParamsTest { @Test - fun createProjectLogFetchPostParams() { + fun create() { ProjectLogFetchPostParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") @@ -31,64 +20,45 @@ class ProjectLogFetchPostParamsTest { } @Test - fun getBody() { + fun pathParams() { + val params = + ProjectLogFetchPostParams.builder() + .projectId("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 body() { val params = ProjectLogFetchPostParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.cursor()).isEqualTo("cursor") - assertThat(body.filters()) - .isEqualTo( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - assertThat(body.limit()).isEqualTo(123L) + assertThat(body.limit()).isEqualTo(0L) assertThat(body.maxRootSpanId()).isEqualTo("max_root_span_id") assertThat(body.maxXactId()).isEqualTo("max_xact_id") assertThat(body.version()).isEqualTo("version") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ProjectLogFetchPostParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - ProjectLogFetchPostParams.builder() - .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "projectId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogInsertParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogInsertParamsTest.kt index 4540c135..1cf5e777 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogInsertParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogInsertParamsTest.kt @@ -2,200 +2,220 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectLogInsertParamsTest { +internal class ProjectLogInsertParamsTest { @Test - fun createProjectLogInsertParams() { + fun create() { ProjectLogInsertParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ProjectLogInsertParams.Event.ofInsertProjectLogsEventReplace( - InsertProjectLogsEventReplace.builder() + .addEvent( + InsertProjectLogsEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertProjectLogsEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertProjectLogsEventReplace.Metadata.builder().build()) - .metrics( - InsertProjectLogsEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertProjectLogsEventReplace.Scores.builder().build()) - .spanAttributes( - InsertProjectLogsEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertProjectLogsEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") .build() ) - ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() } @Test - fun getBody() { + fun pathParams() { val params = ProjectLogInsertParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ProjectLogInsertParams.Event.ofInsertProjectLogsEventReplace( - InsertProjectLogsEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertProjectLogsEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertProjectLogsEventReplace.Metadata.builder().build()) - .metrics( - InsertProjectLogsEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertProjectLogsEventReplace.Scores.builder().build()) - .spanAttributes( - InsertProjectLogsEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertProjectLogsEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - ) - ) - ) + .addEvent(InsertProjectLogsEvent.builder().build()) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.events()) - .isEqualTo( - listOf( - ProjectLogInsertParams.Event.ofInsertProjectLogsEventReplace( - InsertProjectLogsEventReplace.builder() - .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertProjectLogsEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertProjectLogsEventReplace.Metadata.builder().build()) - .metrics( - InsertProjectLogsEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertProjectLogsEventReplace.Scores.builder().build()) - .spanAttributes( - InsertProjectLogsEventReplace.SpanAttributes.builder() - .name("name") - .type(InsertProjectLogsEventReplace.SpanAttributes.Type.LLM) - .build() - ) - .tags(listOf("string")) - .build() - ) - ) - ) + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = ProjectLogInsertParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ProjectLogInsertParams.Event.ofInsertProjectLogsEventReplace( - InsertProjectLogsEventReplace.builder().build() + .addEvent( + InsertProjectLogsEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() ) - ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.events()) - .isEqualTo( - listOf( - ProjectLogInsertParams.Event.ofInsertProjectLogsEventReplace( - InsertProjectLogsEventReplace.builder().build() + .containsExactly( + InsertProjectLogsEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() ) - ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = ProjectLogInsertParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ProjectLogInsertParams.Event.ofInsertProjectLogsEventReplace( - InsertProjectLogsEventReplace.builder().build() - ) - ) - ) + .addEvent(InsertProjectLogsEvent.builder().build()) .build() - assertThat(params).isNotNull - // path param "projectId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.events()).containsExactly(InsertProjectLogsEvent.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogsEventTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogsEventTest.kt index b5897efb..59844d9e 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogsEventTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectLogsEventTest.kt @@ -2,15 +2,17 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectLogsEventTest { +internal class ProjectLogsEventTest { @Test - fun createProjectLogsEvent() { + fun create() { val projectLogsEvent = ProjectLogsEvent.builder() .id("id") @@ -25,34 +27,46 @@ class ProjectLogsEventTest { ProjectLogsEvent.Context.builder() .callerFilename("caller_filename") .callerFunctionname("caller_functionname") - .callerLineno(123L) + .callerLineno(0L) .build() ) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(ProjectLogsEvent.Metadata.builder().build()) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ProjectLogsEvent.Metadata.builder().model("model").build()) .metrics( ProjectLogsEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) .build() ) - .output(JsonNull.of()) - .scores(ProjectLogsEvent.Scores.builder().build()) - .spanAttributes( - ProjectLogsEvent.SpanAttributes.builder() - .name("name") - .type(ProjectLogsEvent.SpanAttributes.Type.LLM) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") .build() ) - .spanParents(listOf("string")) - .tags(listOf("string")) + .output(JsonValue.from(mapOf())) + .scores( + ProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .addSpanParent("string") + .addTag("string") .build() - assertThat(projectLogsEvent).isNotNull + assertThat(projectLogsEvent.id()).isEqualTo("id") assertThat(projectLogsEvent._xactId()).isEqualTo("_xact_id") assertThat(projectLogsEvent.created()) @@ -67,34 +81,114 @@ class ProjectLogsEventTest { ProjectLogsEvent.Context.builder() .callerFilename("caller_filename") .callerFunctionname("caller_functionname") - .callerLineno(123L) + .callerLineno(0L) .build() ) - assertThat(projectLogsEvent._error()).isEqualTo(JsonNull.of()) - assertThat(projectLogsEvent._expected()).isEqualTo(JsonNull.of()) - assertThat(projectLogsEvent._input()).isEqualTo(JsonNull.of()) + assertThat(projectLogsEvent._error()).isEqualTo(JsonValue.from(mapOf())) + assertThat(projectLogsEvent._expected()).isEqualTo(JsonValue.from(mapOf())) + assertThat(projectLogsEvent._input()).isEqualTo(JsonValue.from(mapOf())) + assertThat(projectLogsEvent.isRoot()).isEqualTo(true) assertThat(projectLogsEvent.metadata()) - .isEqualTo(ProjectLogsEvent.Metadata.builder().build()) + .isEqualTo(ProjectLogsEvent.Metadata.builder().model("model").build()) assertThat(projectLogsEvent.metrics()) .isEqualTo( ProjectLogsEvent.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) .build() ) - assertThat(projectLogsEvent._output()).isEqualTo(JsonNull.of()) - assertThat(projectLogsEvent.scores()).isEqualTo(ProjectLogsEvent.Scores.builder().build()) - assertThat(projectLogsEvent.spanAttributes()) + assertThat(projectLogsEvent.origin()) + .isEqualTo( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + assertThat(projectLogsEvent._output()).isEqualTo(JsonValue.from(mapOf())) + assertThat(projectLogsEvent.scores()) .isEqualTo( - ProjectLogsEvent.SpanAttributes.builder() - .name("name") - .type(ProjectLogsEvent.SpanAttributes.Type.LLM) + ProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) .build() ) + assertThat(projectLogsEvent.spanAttributes()) + .isEqualTo(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) assertThat(projectLogsEvent.spanParents()).containsExactly("string") assertThat(projectLogsEvent.tags()).containsExactly("string") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectLogsEvent = + ProjectLogsEvent.builder() + .id("id") + ._xactId("_xact_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .logId(ProjectLogsEvent.LogId.G) + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .rootSpanId("root_span_id") + .spanId("span_id") + .context( + ProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .isRoot(true) + .metadata(ProjectLogsEvent.Metadata.builder().model("model").build()) + .metrics( + ProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .scores( + ProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes(SpanAttributes.builder().name("name").type(SpanType.LLM).build()) + .addSpanParent("string") + .addTag("string") + .build() + + val roundtrippedProjectLogsEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectLogsEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectLogsEvent).isEqualTo(projectLogsEvent) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectRetrieveParamsTest.kt index 231a1864..e83306b3 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectRetrieveParamsTest.kt @@ -2,27 +2,25 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectRetrieveParamsTest { +internal class ProjectRetrieveParamsTest { @Test - fun createProjectRetrieveParams() { + fun create() { ProjectRetrieveParams.builder().projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = ProjectRetrieveParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "projectId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCategoryTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCategoryTest.kt index a190a270..3e4d1ce0 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCategoryTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCategoryTest.kt @@ -2,16 +2,32 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreCategoryTest { +internal class ProjectScoreCategoryTest { @Test - fun createProjectScoreCategory() { - val projectScoreCategory = ProjectScoreCategory.builder().name("name").value(42.23).build() - assertThat(projectScoreCategory).isNotNull + fun create() { + val projectScoreCategory = ProjectScoreCategory.builder().name("name").value(0.0).build() + assertThat(projectScoreCategory.name()).isEqualTo("name") - assertThat(projectScoreCategory.value()).isEqualTo(42.23) + assertThat(projectScoreCategory.value()).isEqualTo(0.0) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectScoreCategory = ProjectScoreCategory.builder().name("name").value(0.0).build() + + val roundtrippedProjectScoreCategory = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectScoreCategory), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectScoreCategory).isEqualTo(projectScoreCategory) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreConfigTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreConfigTest.kt index d41a7b15..cfedc0fb 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreConfigTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreConfigTest.kt @@ -2,56 +2,80 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreConfigTest { +internal class ProjectScoreConfigTest { @Test - fun createProjectScoreConfig() { + fun create() { val projectScoreConfig = ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() - assertThat(projectScoreConfig).isNotNull - assertThat(projectScoreConfig.destination()) - .isEqualTo(ProjectScoreConfig.Destination.EXPECTED) + + assertThat(projectScoreConfig.destination()).isEqualTo("destination") assertThat(projectScoreConfig.multiSelect()).isEqualTo(true) assertThat(projectScoreConfig.online()) .isEqualTo( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectScoreConfig = + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + + val roundtrippedProjectScoreConfig = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectScoreConfig), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectScoreConfig).isEqualTo(projectScoreConfig) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParamsTest.kt index a2b3b31e..9e42c1fb 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreCreateParamsTest.kt @@ -2,40 +2,35 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreCreateParamsTest { +internal class ProjectScoreCreateParamsTest { @Test - fun createProjectScoreCreateParams() { + fun create() { ProjectScoreCreateParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) - .projectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -45,73 +40,64 @@ class ProjectScoreCreateParamsTest { } @Test - fun getBody() { + fun body() { val params = ProjectScoreCreateParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) - .projectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type( - OnlineScoreConfig.Scorer.Function.Type.FUNCTION - ) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() ) .description("description") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.scoreType()).isEqualTo(ProjectScoreType.SLIDER) assertThat(body.categories()) .isEqualTo( - ProjectScoreCreateParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + ProjectScoreCreateParams.Categories.ofCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) ) assertThat(body.config()) .isEqualTo( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -120,15 +106,16 @@ class ProjectScoreCreateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ProjectScoreCreateParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.scoreType()).isEqualTo(ProjectScoreType.SLIDER) diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParamsTest.kt index 896f79a5..c90b6173 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreDeleteParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreDeleteParamsTest { +internal class ProjectScoreDeleteParamsTest { @Test - fun createProjectScoreDeleteParams() { + fun create() { ProjectScoreDeleteParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = ProjectScoreDeleteParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "projectScoreId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreListPageResponseTest.kt new file mode 100644 index 00000000..27b1a1d2 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreListPageResponseTest.kt @@ -0,0 +1,143 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ProjectScoreListPageResponseTest { + + @Test + fun create() { + val projectScoreListPageResponse = + ProjectScoreListPageResponse.builder() + .addObject( + ProjectScore.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .scoreType(ProjectScoreType.SLIDER) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) + ) + .config( + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type( + OnlineScoreConfig.Scorer.Function.Type.FUNCTION + ) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .position("position") + .build() + ) + .build() + + assertThat(projectScoreListPageResponse.objects()) + .containsExactly( + ProjectScore.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .scoreType(ProjectScoreType.SLIDER) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) + ) + .config( + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .position("position") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectScoreListPageResponse = + ProjectScoreListPageResponse.builder() + .addObject( + ProjectScore.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .scoreType(ProjectScoreType.SLIDER) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) + ) + .config( + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type( + OnlineScoreConfig.Scorer.Function.Type.FUNCTION + ) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .position("position") + .build() + ) + .build() + + val roundtrippedProjectScoreListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectScoreListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectScoreListPageResponse).isEqualTo(projectScoreListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreListParamsTest.kt index 7832ecb6..e1ff4653 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreListParamsTest.kt @@ -2,72 +2,66 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreListParamsTest { +internal class ProjectScoreListParamsTest { @Test - fun createProjectScoreListParams() { + fun create() { ProjectScoreListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ProjectScoreListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") .projectScoreName("project_score_name") - .scoreType(ProjectScoreListParams.ScoreType.ofProjectScoreType(ProjectScoreType.SLIDER)) + .scoreType(ProjectScoreType.SLIDER) .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = ProjectScoreListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ProjectScoreListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") .projectScoreName("project_score_name") - .scoreType( - ProjectScoreListParams.ScoreType.ofProjectScoreType(ProjectScoreType.SLIDER) - ) + .scoreType(ProjectScoreType.SLIDER) .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf( - ProjectScoreListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .toString() - ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("project_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("project_name", listOf("project_name")) - expected.put("project_score_name", listOf("project_score_name")) - expected.put( - "score_type", - listOf( - ProjectScoreListParams.ScoreType.ofProjectScoreType(ProjectScoreType.SLIDER) - .toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("project_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("project_name", "project_name") + .put("project_score_name", "project_score_name") + .put("score_type", "slider") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - ) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = ProjectScoreListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParamsTest.kt index dd18f1f5..029eb02d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreReplaceParamsTest.kt @@ -2,40 +2,35 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreReplaceParamsTest { +internal class ProjectScoreReplaceParamsTest { @Test - fun createProjectScoreReplaceParams() { + fun create() { ProjectScoreReplaceParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) - .projectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -45,73 +40,64 @@ class ProjectScoreReplaceParamsTest { } @Test - fun getBody() { + fun body() { val params = ProjectScoreReplaceParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) - .projectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type( - OnlineScoreConfig.Scorer.Function.Type.FUNCTION - ) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() ) .description("description") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.scoreType()).isEqualTo(ProjectScoreType.SLIDER) assertThat(body.categories()) .isEqualTo( - ProjectScoreReplaceParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + ProjectScoreReplaceParams.Categories.ofCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) ) assertThat(body.config()) .isEqualTo( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -120,15 +106,16 @@ class ProjectScoreReplaceParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ProjectScoreReplaceParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.scoreType()).isEqualTo(ProjectScoreType.SLIDER) diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParamsTest.kt index 9237a10b..8bfde8f2 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreRetrieveParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreRetrieveParamsTest { +internal class ProjectScoreRetrieveParamsTest { @Test - fun createProjectScoreRetrieveParams() { + fun create() { ProjectScoreRetrieveParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = ProjectScoreRetrieveParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "projectScoreId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreTest.kt index 36aa4861..fce95fb9 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreTest { +internal class ProjectScoreTest { @Test - fun createProjectScore() { + fun create() { val projectScore = ProjectScore.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -17,32 +19,24 @@ class ProjectScoreTest { .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .categories( - ProjectScore.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) - ) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type( - OnlineScoreConfig.Scorer.Function.Type.FUNCTION - ) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -51,7 +45,7 @@ class ProjectScoreTest { .description("description") .position("position") .build() - assertThat(projectScore).isNotNull + assertThat(projectScore.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(projectScore.name()).isEqualTo("name") assertThat(projectScore.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -59,30 +53,26 @@ class ProjectScoreTest { assertThat(projectScore.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(projectScore.categories()) .isEqualTo( - ProjectScore.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + ProjectScore.Categories.ofCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) ) assertThat(projectScore.config()) .isEqualTo( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -92,4 +82,50 @@ class ProjectScoreTest { assertThat(projectScore.description()).isEqualTo("description") assertThat(projectScore.position()).isEqualTo("position") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectScore = + ProjectScore.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .scoreType(ProjectScoreType.SLIDER) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) + ) + .config( + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .position("position") + .build() + + val roundtrippedProjectScore = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectScore), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectScore).isEqualTo(projectScore) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParamsTest.kt index 0b53a466..37473fdf 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectScoreUpdateParamsTest.kt @@ -2,40 +2,33 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectScoreUpdateParamsTest { +internal class ProjectScoreUpdateParamsTest { @Test - fun createProjectScoreUpdateParams() { + fun create() { ProjectScoreUpdateParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .categories( - ProjectScoreUpdateParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) - ) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -47,36 +40,40 @@ class ProjectScoreUpdateParamsTest { } @Test - fun getBody() { + fun pathParams() { val params = ProjectScoreUpdateParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .categories( - ProjectScoreUpdateParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) - ) + .build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun body() { + val params = + ProjectScoreUpdateParams.builder() + .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type( - OnlineScoreConfig.Scorer.Function.Type.FUNCTION - ) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -85,34 +82,31 @@ class ProjectScoreUpdateParamsTest { .name("name") .scoreType(ProjectScoreType.SLIDER) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.categories()) .isEqualTo( - ProjectScoreUpdateParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) + ProjectScoreUpdateParams.Categories.ofCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) ) assertThat(body.config()) .isEqualTo( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -123,25 +117,12 @@ class ProjectScoreUpdateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ProjectScoreUpdateParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - ProjectScoreUpdateParams.builder() - .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - assertThat(params).isNotNull - // path param "projectScoreId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectSettingsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectSettingsTest.kt index d4425e9c..a6f76705 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectSettingsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectSettingsTest.kt @@ -2,15 +2,66 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectSettingsTest { +internal class ProjectSettingsTest { @Test - fun createProjectSettings() { - val projectSettings = ProjectSettings.builder().comparisonKey("comparison_key").build() - assertThat(projectSettings).isNotNull + fun create() { + val projectSettings = + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + + assertThat(projectSettings.baselineExperimentId()) + .isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(projectSettings.comparisonKey()).isEqualTo("comparison_key") + assertThat(projectSettings.spanFieldOrder()) + .containsExactly( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectSettings = + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + + val roundtrippedProjectSettings = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectSettings), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectSettings).isEqualTo(projectSettings) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagCreateParamsTest.kt index 111ab845..a8ba4ca2 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagCreateParamsTest.kt @@ -2,14 +2,13 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTagCreateParamsTest { +internal class ProjectTagCreateParamsTest { @Test - fun createProjectTagCreateParams() { + fun create() { ProjectTagCreateParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -19,7 +18,7 @@ class ProjectTagCreateParamsTest { } @Test - fun getBody() { + fun body() { val params = ProjectTagCreateParams.builder() .name("name") @@ -27,8 +26,9 @@ class ProjectTagCreateParamsTest { .color("color") .description("description") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.color()).isEqualTo("color") @@ -36,14 +36,15 @@ class ProjectTagCreateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ProjectTagCreateParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParamsTest.kt index 12369e03..16087334 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagDeleteParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTagDeleteParamsTest { +internal class ProjectTagDeleteParamsTest { @Test - fun createProjectTagDeleteParams() { + fun create() { ProjectTagDeleteParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = ProjectTagDeleteParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "projectTagId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagListPageResponseTest.kt new file mode 100644 index 00000000..4dd2fc1f --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagListPageResponseTest.kt @@ -0,0 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ProjectTagListPageResponseTest { + + @Test + fun create() { + val projectTagListPageResponse = + ProjectTagListPageResponse.builder() + .addObject( + ProjectTag.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .build() + ) + .build() + + assertThat(projectTagListPageResponse.objects()) + .containsExactly( + ProjectTag.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectTagListPageResponse = + ProjectTagListPageResponse.builder() + .addObject( + ProjectTag.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .build() + ) + .build() + + val roundtrippedProjectTagListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectTagListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectTagListPageResponse).isEqualTo(projectTagListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagListParamsTest.kt index 091272bb..5b43e3ad 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagListParamsTest.kt @@ -2,18 +2,18 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTagListParamsTest { +internal class ProjectTagListParamsTest { @Test - fun createProjectTagListParams() { + fun create() { ProjectTagListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ProjectTagListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") @@ -23,39 +23,42 @@ class ProjectTagListParamsTest { } @Test - fun getQueryParams() { + fun queryParams() { val params = ProjectTagListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ProjectTagListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") .projectTagName("project_tag_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf( - ProjectTagListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("project_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("project_name", "project_name") + .put("project_tag_name", "project_tag_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("project_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("project_name", listOf("project_name")) - expected.put("project_tag_name", listOf("project_tag_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = ProjectTagListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParamsTest.kt index bec95fa1..77f1b073 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagReplaceParamsTest.kt @@ -2,14 +2,13 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTagReplaceParamsTest { +internal class ProjectTagReplaceParamsTest { @Test - fun createProjectTagReplaceParams() { + fun create() { ProjectTagReplaceParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -19,7 +18,7 @@ class ProjectTagReplaceParamsTest { } @Test - fun getBody() { + fun body() { val params = ProjectTagReplaceParams.builder() .name("name") @@ -27,8 +26,9 @@ class ProjectTagReplaceParamsTest { .color("color") .description("description") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.color()).isEqualTo("color") @@ -36,14 +36,15 @@ class ProjectTagReplaceParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ProjectTagReplaceParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParamsTest.kt index cd792595..f7bbf553 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagRetrieveParamsTest.kt @@ -2,29 +2,27 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTagRetrieveParamsTest { +internal class ProjectTagRetrieveParamsTest { @Test - fun createProjectTagRetrieveParams() { + fun create() { ProjectTagRetrieveParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getPathParam() { + fun pathParams() { val params = ProjectTagRetrieveParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "projectTagId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagTest.kt index 188c5d3e..d4adbd79 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTagTest { +internal class ProjectTagTest { @Test - fun createProjectTag() { + fun create() { val projectTag = ProjectTag.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -20,7 +22,7 @@ class ProjectTagTest { .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .description("description") .build() - assertThat(projectTag).isNotNull + assertThat(projectTag.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(projectTag.name()).isEqualTo("name") assertThat(projectTag.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -29,4 +31,27 @@ class ProjectTagTest { assertThat(projectTag.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(projectTag.description()).isEqualTo("description") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val projectTag = + ProjectTag.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .build() + + val roundtrippedProjectTag = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectTag), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectTag).isEqualTo(projectTag) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParamsTest.kt index 9b5ac6a1..c1b0562d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTagUpdateParamsTest.kt @@ -2,14 +2,13 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTagUpdateParamsTest { +internal class ProjectTagUpdateParamsTest { @Test - fun createProjectTagUpdateParams() { + fun create() { ProjectTagUpdateParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .color("color") @@ -19,41 +18,41 @@ class ProjectTagUpdateParamsTest { } @Test - fun getBody() { + fun pathParams() { val params = ProjectTagUpdateParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .color("color") - .description("description") - .name("name") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.color()).isEqualTo("color") - assertThat(body.description()).isEqualTo("description") - assertThat(body.name()).isEqualTo("name") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getBodyWithoutOptionalFields() { + fun body() { val params = ProjectTagUpdateParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .description("description") + .name("name") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + + assertThat(body.color()).isEqualTo("color") + assertThat(body.description()).isEqualTo("description") + assertThat(body.name()).isEqualTo("name") } @Test - fun getPathParam() { + fun bodyWithoutOptionalFields() { val params = ProjectTagUpdateParams.builder() .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(params).isNotNull - // path param "projectTagId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTest.kt index 9aaed9c0..513a4e71 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectTest { +internal class ProjectTest { @Test - fun createProject() { + fun create() { val project = Project.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -17,17 +19,76 @@ class ProjectTest { .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .settings(ProjectSettings.builder().comparisonKey("comparison_key").build()) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(project).isNotNull + assertThat(project.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(project.name()).isEqualTo("name") assertThat(project.orgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(project.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(project.deletedAt()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(project.settings()) - .isEqualTo(ProjectSettings.builder().comparisonKey("comparison_key").build()) + .isEqualTo( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) assertThat(project.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val project = + Project.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedProject = + jsonMapper.readValue(jsonMapper.writeValueAsString(project), jacksonTypeRef()) + + assertThat(roundtrippedProject).isEqualTo(project) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectUpdateParamsTest.kt index 9ea7f42d..70e76593 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ProjectUpdateParamsTest.kt @@ -2,52 +2,90 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ProjectUpdateParamsTest { +internal class ProjectUpdateParamsTest { @Test - fun createProjectUpdateParams() { + fun create() { ProjectUpdateParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") - .settings(ProjectSettings.builder().comparisonKey("comparison_key").build()) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) .build() } @Test - fun getBody() { + fun pathParams() { + val params = + ProjectUpdateParams.builder().projectId("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 body() { val params = ProjectUpdateParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") - .settings(ProjectSettings.builder().comparisonKey("comparison_key").build()) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.settings()) - .isEqualTo(ProjectSettings.builder().comparisonKey("comparison_key").build()) + .isEqualTo( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ProjectUpdateParams.builder().projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - ProjectUpdateParams.builder().projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "projectId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptCreateParamsTest.kt index f7b21942..72b3c026 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptCreateParamsTest.kt @@ -2,60 +2,63 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptCreateParamsTest { +internal class PromptCreateParamsTest { @Test - fun createPromptCreateParams() { + fun create() { PromptCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionType(PromptCreateParams.FunctionType.LLM) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -69,85 +72,86 @@ class PromptCreateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() } @Test - fun getBody() { + fun body() { val params = PromptCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionType(PromptCreateParams.FunctionType.LLM) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -161,81 +165,83 @@ class PromptCreateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") assertThat(body.functionType()).isEqualTo(PromptCreateParams.FunctionType.LLM) assertThat(body.promptData()) .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -249,46 +255,45 @@ class PromptCreateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - assertThat(body.tags()).isEqualTo(listOf("string")) + assertThat(body.tags()).containsExactly("string") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = PromptCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDataTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDataTest.kt index 5a054cfc..8efdcd63 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDataTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDataTest.kt @@ -2,52 +2,55 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptDataTest { +internal class PromptDataTest { @Test - fun createPromptData() { + fun create() { val promptData = PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams.ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall.UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice.UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -61,67 +64,66 @@ class PromptDataTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() - assertThat(promptData).isNotNull + assertThat(promptData.options()) .isEqualTo( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall.ofAuto( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .Auto - .AUTO + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall.UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .Type + .JSON_OBJECT ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams.ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice.UnionMember0.AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -137,7 +139,11 @@ class PromptDataTest { assertThat(promptData.parser()) .isEqualTo( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() @@ -161,4 +167,91 @@ class PromptDataTest { ) ) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val promptData = + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall.UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice.UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + + val roundtrippedPromptData = + jsonMapper.readValue( + jsonMapper.writeValueAsString(promptData), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPromptData).isEqualTo(promptData) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDeleteParamsTest.kt index a819f9d2..45b20f34 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptDeleteParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptDeleteParamsTest { +internal class PromptDeleteParamsTest { @Test - fun createPromptDeleteParams() { + fun create() { PromptDeleteParams.builder().promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = PromptDeleteParams.builder().promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "promptId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptListPageResponseTest.kt new file mode 100644 index 00000000..9894bafc --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptListPageResponseTest.kt @@ -0,0 +1,348 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PromptListPageResponseTest { + + @Test + fun create() { + val promptListPageResponse = + PromptListPageResponse.builder() + .addObject( + Prompt.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .logId(Prompt.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionType(Prompt.FunctionType.LLM) + .metadata( + Prompt.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams + .FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams + .ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + .build() + + assertThat(promptListPageResponse.objects()) + .containsExactly( + Prompt.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .logId(Prompt.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionType(Prompt.FunctionType.LLM) + .metadata( + Prompt.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val promptListPageResponse = + PromptListPageResponse.builder() + .addObject( + Prompt.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .logId(Prompt.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionType(Prompt.FunctionType.LLM) + .metadata( + Prompt.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams + .FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams + .ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + .build() + + val roundtrippedPromptListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(promptListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPromptListPageResponse).isEqualTo(promptListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptListParamsTest.kt index a2c57163..ef6a5e48 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptListParamsTest.kt @@ -2,18 +2,18 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptListParamsTest { +internal class PromptListParamsTest { @Test - fun createPromptListParams() { + fun create() { PromptListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(PromptListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") @@ -25,12 +25,12 @@ class PromptListParamsTest { } @Test - fun getQueryParams() { + fun queryParams() { val params = PromptListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(PromptListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .projectName("project_name") @@ -39,27 +39,32 @@ class PromptListParamsTest { .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .version("version") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf(PromptListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("project_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("project_name", listOf("project_name")) - expected.put("prompt_name", listOf("prompt_name")) - expected.put("slug", listOf("slug")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("version", listOf("version")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("project_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("project_name", "project_name") + .put("prompt_name", "prompt_name") + .put("slug", "slug") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("version", "version") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = PromptListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptOptionsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptOptionsTest.kt new file mode 100644 index 00000000..837c0898 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptOptionsTest.kt @@ -0,0 +1,134 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.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 PromptOptionsTest { + + @Test + fun create() { + val promptOptions = + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall.UnionMember0.AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort(PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice.UnionMember0.AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + + assertThat(promptOptions.model()).isEqualTo("model") + assertThat(promptOptions.params()) + .isEqualTo( + PromptOptions.Params.ofOpenAIModel( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall.UnionMember0.AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort(PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice.UnionMember0.AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + ) + assertThat(promptOptions.position()).isEqualTo("position") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val promptOptions = + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall.UnionMember0.AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort(PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams.ResponseFormat.JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice.UnionMember0.AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + + val roundtrippedPromptOptions = + jsonMapper.readValue( + jsonMapper.writeValueAsString(promptOptions), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPromptOptions).isEqualTo(promptOptions) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptReplaceParamsTest.kt index 3031f48e..f7beae13 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptReplaceParamsTest.kt @@ -2,60 +2,63 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptReplaceParamsTest { +internal class PromptReplaceParamsTest { @Test - fun createPromptReplaceParams() { + fun create() { PromptReplaceParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionType(PromptReplaceParams.FunctionType.LLM) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -69,85 +72,86 @@ class PromptReplaceParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() } @Test - fun getBody() { + fun body() { val params = PromptReplaceParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionType(PromptReplaceParams.FunctionType.LLM) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -161,81 +165,83 @@ class PromptReplaceParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") assertThat(body.functionType()).isEqualTo(PromptReplaceParams.FunctionType.LLM) assertThat(body.promptData()) .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -249,46 +255,45 @@ class PromptReplaceParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - assertThat(body.tags()).isEqualTo(listOf("string")) + assertThat(body.tags()).containsExactly("string") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = PromptReplaceParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.slug()).isEqualTo("slug") + assertThat(body.slug()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptRetrieveParamsTest.kt index d8aa5099..97f8cb26 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptRetrieveParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptRetrieveParamsTest { +internal class PromptRetrieveParamsTest { @Test - fun createPromptRetrieveParams() { + fun create() { PromptRetrieveParams.builder().promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = PromptRetrieveParams.builder().promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "promptId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptTest.kt index a1a02495..bfa3aae7 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptTest.kt @@ -2,14 +2,17 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptTest { +internal class PromptTest { @Test - fun createPrompt() { + fun create() { val prompt = Prompt.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -22,48 +25,55 @@ class PromptTest { .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .description("description") .functionType(Prompt.FunctionType.LLM) - .metadata(Prompt.Metadata.builder().build()) + .metadata( + Prompt.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -77,34 +87,32 @@ class PromptTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() - assertThat(prompt).isNotNull + assertThat(prompt.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(prompt._xactId()).isEqualTo("_xact_id") assertThat(prompt.logId()).isEqualTo(Prompt.LogId.P) @@ -115,48 +123,56 @@ class PromptTest { assertThat(prompt.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(prompt.description()).isEqualTo("description") assertThat(prompt.functionType()).isEqualTo(Prompt.FunctionType.LLM) - assertThat(prompt.metadata()).isEqualTo(Prompt.Metadata.builder().build()) + assertThat(prompt.metadata()) + .isEqualTo( + Prompt.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) assertThat(prompt.promptData()) .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -170,31 +186,138 @@ class PromptTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + assertThat(prompt.tags()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val prompt = + Prompt.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + ._xactId("_xact_id") + .logId(Prompt.LogId.P) + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("slug") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .functionType(Prompt.FunctionType.LLM) + .metadata( + Prompt.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( PromptData.Prompt.Completion.builder() .content("content") .type(PromptData.Prompt.Completion.Type.COMPLETION) .build() ) - ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) - ) - .build() - ) - assertThat(prompt.tags()).containsExactly("string") + .build() + ) + .addTag("string") + .build() + + val roundtrippedPrompt = + jsonMapper.readValue(jsonMapper.writeValueAsString(prompt), jacksonTypeRef()) + + assertThat(roundtrippedPrompt).isEqualTo(prompt) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptUpdateParamsTest.kt index c75ca8b0..47ecb6d1 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/PromptUpdateParamsTest.kt @@ -2,14 +2,14 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class PromptUpdateParamsTest { +internal class PromptUpdateParamsTest { @Test - fun createPromptUpdateParams() { + fun create() { PromptUpdateParams.builder() .promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") @@ -17,43 +17,46 @@ class PromptUpdateParamsTest { .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -67,38 +70,46 @@ class PromptUpdateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) .slug("slug") - .tags(listOf("string")) + .addTag("string") .build() } @Test - fun getBody() { + fun pathParams() { + val params = + PromptUpdateParams.builder().promptId("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 body() { val params = PromptUpdateParams.builder() .promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -107,44 +118,47 @@ class PromptUpdateParamsTest { .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -158,79 +172,81 @@ class PromptUpdateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) .slug("slug") - .tags(listOf("string")) + .addTag("string") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.description()).isEqualTo("description") assertThat(body.name()).isEqualTo("name") assertThat(body.promptData()) .isEqualTo( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams.FunctionCall - .ofAuto( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams.ReasoningEffort.LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams.ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -244,51 +260,38 @@ class PromptUpdateParamsTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) assertThat(body.slug()).isEqualTo("slug") - assertThat(body.tags()).isEqualTo(listOf("string")) + assertThat(body.tags()).containsExactly("string") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = PromptUpdateParams.builder().promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - PromptUpdateParams.builder().promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "promptId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RepoInfoTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RepoInfoTest.kt index 2473839f..4fa4ae1c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RepoInfoTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RepoInfoTest.kt @@ -2,13 +2,15 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RepoInfoTest { +internal class RepoInfoTest { @Test - fun createRepoInfo() { + fun create() { val repoInfo = RepoInfo.builder() .authorEmail("author_email") @@ -21,7 +23,7 @@ class RepoInfoTest { .gitDiff("git_diff") .tag("tag") .build() - assertThat(repoInfo).isNotNull + assertThat(repoInfo.authorEmail()).isEqualTo("author_email") assertThat(repoInfo.authorName()).isEqualTo("author_name") assertThat(repoInfo.branch()).isEqualTo("branch") @@ -32,4 +34,29 @@ class RepoInfoTest { assertThat(repoInfo.gitDiff()).isEqualTo("git_diff") assertThat(repoInfo.tag()).isEqualTo("tag") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val repoInfo = + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + + val roundtrippedRepoInfo = + jsonMapper.readValue( + jsonMapper.writeValueAsString(repoInfo), + jacksonTypeRef(), + ) + + assertThat(roundtrippedRepoInfo).isEqualTo(repoInfo) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleCreateParamsTest.kt index e4500a98..e8721be3 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleCreateParamsTest.kt @@ -2,75 +2,64 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RoleCreateParamsTest { +internal class RoleCreateParamsTest { @Test - fun createRoleCreateParams() { + fun create() { RoleCreateParams.builder() - .name("name") + .name("x") .description("description") - .memberPermissions( - listOf( - RoleCreateParams.MemberPermission.builder() - .permission(RoleCreateParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleCreateParams.MemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .addMemberPermission( + RoleCreateParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .memberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() } @Test - fun getBody() { + fun body() { val params = RoleCreateParams.builder() - .name("name") + .name("x") .description("description") - .memberPermissions( - listOf( - RoleCreateParams.MemberPermission.builder() - .permission(RoleCreateParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleCreateParams.MemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .addMemberPermission( + RoleCreateParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .memberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") assertThat(body.memberPermissions()) - .isEqualTo( - listOf( - RoleCreateParams.MemberPermission.builder() - .permission(RoleCreateParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleCreateParams.MemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .containsExactly( + RoleCreateParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - assertThat(body.memberRoles()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + assertThat(body.memberRoles()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.orgName()).isEqualTo("org_name") } @Test - fun getBodyWithoutOptionalFields() { - val params = RoleCreateParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + fun bodyWithoutOptionalFields() { + val params = RoleCreateParams.builder().name("x").build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleDeleteParamsTest.kt index df2e651a..8a61140e 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleDeleteParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RoleDeleteParamsTest { +internal class RoleDeleteParamsTest { @Test - fun createRoleDeleteParams() { + fun create() { RoleDeleteParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = RoleDeleteParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "roleId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleListPageResponseTest.kt new file mode 100644 index 00000000..0cdd38e4 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleListPageResponseTest.kt @@ -0,0 +1,91 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class RoleListPageResponseTest { + + @Test + fun create() { + val roleListPageResponse = + RoleListPageResponse.builder() + .addObject( + Role.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberPermission( + Role.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(roleListPageResponse.objects()) + .containsExactly( + Role.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberPermission( + Role.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val roleListPageResponse = + RoleListPageResponse.builder() + .addObject( + Role.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberPermission( + Role.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedRoleListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(roleListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedRoleListPageResponse).isEqualTo(roleListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleListParamsTest.kt index 2db9679b..c023fec1 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleListParamsTest.kt @@ -2,18 +2,18 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RoleListParamsTest { +internal class RoleListParamsTest { @Test - fun createRoleListParams() { + fun create() { RoleListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(RoleListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .roleName("role_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -21,33 +21,38 @@ class RoleListParamsTest { } @Test - fun getQueryParams() { + fun queryParams() { val params = RoleListParams.builder() .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(RoleListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .roleName("role_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf(RoleListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("role_name", listOf("role_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("role_name", "role_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = RoleListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleReplaceParamsTest.kt index 299ccd32..d7575012 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleReplaceParamsTest.kt @@ -2,75 +2,64 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RoleReplaceParamsTest { +internal class RoleReplaceParamsTest { @Test - fun createRoleReplaceParams() { + fun create() { RoleReplaceParams.builder() - .name("name") + .name("x") .description("description") - .memberPermissions( - listOf( - RoleReplaceParams.MemberPermission.builder() - .permission(RoleReplaceParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleReplaceParams.MemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .addMemberPermission( + RoleReplaceParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .memberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() } @Test - fun getBody() { + fun body() { val params = RoleReplaceParams.builder() - .name("name") + .name("x") .description("description") - .memberPermissions( - listOf( - RoleReplaceParams.MemberPermission.builder() - .permission(RoleReplaceParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleReplaceParams.MemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .addMemberPermission( + RoleReplaceParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .memberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") assertThat(body.description()).isEqualTo("description") assertThat(body.memberPermissions()) - .isEqualTo( - listOf( - RoleReplaceParams.MemberPermission.builder() - .permission(RoleReplaceParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleReplaceParams.MemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .containsExactly( + RoleReplaceParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - assertThat(body.memberRoles()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + assertThat(body.memberRoles()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.orgName()).isEqualTo("org_name") } @Test - fun getBodyWithoutOptionalFields() { - val params = RoleReplaceParams.builder().name("name").build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.name()).isEqualTo("name") + fun bodyWithoutOptionalFields() { + val params = RoleReplaceParams.builder().name("x").build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("x") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleRetrieveParamsTest.kt index d0791c4d..27d753fa 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleRetrieveParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RoleRetrieveParamsTest { +internal class RoleRetrieveParamsTest { @Test - fun createRoleRetrieveParams() { + fun create() { RoleRetrieveParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = RoleRetrieveParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "roleId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleTest.kt index 758a8e07..6125fc6f 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RoleTest { +internal class RoleTest { @Test - fun createRole() { + fun create() { val role = Role.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -17,21 +19,17 @@ class RoleTest { .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .description("description") - .memberPermissions( - listOf( - Role.MemberPermission.builder() - .permission(Role.MemberPermission.Permission.CREATE) - .restrictObjectType( - Role.MemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .addMemberPermission( + Role.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .memberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - assertThat(role).isNotNull + assertThat(role.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(role.name()).isEqualTo("name") assertThat(role.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -40,12 +38,39 @@ class RoleTest { assertThat(role.memberPermissions()) .containsExactly( Role.MemberPermission.builder() - .permission(Role.MemberPermission.Permission.CREATE) - .restrictObjectType(Role.MemberPermission.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .build() ) assertThat(role.memberRoles()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(role.orgId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(role.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val role = + Role.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .addMemberPermission( + Role.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedRole = + jsonMapper.readValue(jsonMapper.writeValueAsString(role), jacksonTypeRef()) + + assertThat(roundtrippedRole).isEqualTo(role) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleUpdateParamsTest.kt index 46274c48..8abd6e4e 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/RoleUpdateParamsTest.kt @@ -2,121 +2,94 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class RoleUpdateParamsTest { +internal class RoleUpdateParamsTest { @Test - fun createRoleUpdateParams() { + fun create() { RoleUpdateParams.builder() .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .addMemberPermissions( - listOf( - RoleUpdateParams.AddMemberPermission.builder() - .permission(RoleUpdateParams.AddMemberPermission.Permission.CREATE) - .restrictObjectType( - RoleUpdateParams.AddMemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .addAddMemberPermission( + RoleUpdateParams.AddMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .addMemberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addAddMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .name("name") - .removeMemberPermissions( - listOf( - RoleUpdateParams.RemoveMemberPermission.builder() - .permission(RoleUpdateParams.RemoveMemberPermission.Permission.CREATE) - .restrictObjectType( - RoleUpdateParams.RemoveMemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .name("x") + .addRemoveMemberPermission( + RoleUpdateParams.RemoveMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .removeMemberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addRemoveMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getBody() { + fun pathParams() { + val params = + RoleUpdateParams.builder().roleId("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 body() { val params = RoleUpdateParams.builder() .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .addMemberPermissions( - listOf( - RoleUpdateParams.AddMemberPermission.builder() - .permission(RoleUpdateParams.AddMemberPermission.Permission.CREATE) - .restrictObjectType( - RoleUpdateParams.AddMemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .addAddMemberPermission( + RoleUpdateParams.AddMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .addMemberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addAddMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .name("name") - .removeMemberPermissions( - listOf( - RoleUpdateParams.RemoveMemberPermission.builder() - .permission(RoleUpdateParams.RemoveMemberPermission.Permission.CREATE) - .restrictObjectType( - RoleUpdateParams.RemoveMemberPermission.RestrictObjectType - .ORGANIZATION - ) - .build() - ) + .name("x") + .addRemoveMemberPermission( + RoleUpdateParams.RemoveMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .removeMemberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addRemoveMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.addMemberPermissions()) - .isEqualTo( - listOf( - RoleUpdateParams.AddMemberPermission.builder() - .permission(RoleUpdateParams.AddMemberPermission.Permission.CREATE) - .restrictObjectType( - RoleUpdateParams.AddMemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .containsExactly( + RoleUpdateParams.AddMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - assertThat(body.addMemberRoles()).isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + assertThat(body.addMemberRoles()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(body.description()).isEqualTo("description") - assertThat(body.name()).isEqualTo("name") + assertThat(body.name()).isEqualTo("x") assertThat(body.removeMemberPermissions()) - .isEqualTo( - listOf( - RoleUpdateParams.RemoveMemberPermission.builder() - .permission(RoleUpdateParams.RemoveMemberPermission.Permission.CREATE) - .restrictObjectType( - RoleUpdateParams.RemoveMemberPermission.RestrictObjectType.ORGANIZATION - ) - .build() - ) + .containsExactly( + RoleUpdateParams.RemoveMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - assertThat(body.removeMemberRoles()) - .isEqualTo(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + assertThat(body.removeMemberRoles()).containsExactly("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = RoleUpdateParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - val body = params.getBody() - assertThat(body).isNotNull - } - @Test - fun getPathParam() { - val params = - RoleUpdateParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "roleId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ScoreSummaryTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ScoreSummaryTest.kt index ff4f5a7d..0d4b0cc8 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ScoreSummaryTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ScoreSummaryTest.kt @@ -2,26 +2,49 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ScoreSummaryTest { +internal class ScoreSummaryTest { @Test - fun createScoreSummary() { + fun create() { val scoreSummary = ScoreSummary.builder() - .improvements(123L) + .improvements(0L) .name("name") - .regressions(123L) - .score(1.0) - .diff(1.0) + .regressions(0L) + .score(0.0) + .diff(-1.0) .build() - assertThat(scoreSummary).isNotNull - assertThat(scoreSummary.improvements()).isEqualTo(123L) + + assertThat(scoreSummary.improvements()).isEqualTo(0L) assertThat(scoreSummary.name()).isEqualTo("name") - assertThat(scoreSummary.regressions()).isEqualTo(123L) - assertThat(scoreSummary.score()).isEqualTo(1.0) - assertThat(scoreSummary.diff()).isEqualTo(1.0) + assertThat(scoreSummary.regressions()).isEqualTo(0L) + assertThat(scoreSummary.score()).isEqualTo(0.0) + assertThat(scoreSummary.diff()).isEqualTo(-1.0) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val scoreSummary = + ScoreSummary.builder() + .improvements(0L) + .name("name") + .regressions(0L) + .score(0.0) + .diff(-1.0) + .build() + + val roundtrippedScoreSummary = + jsonMapper.readValue( + jsonMapper.writeValueAsString(scoreSummary), + jacksonTypeRef(), + ) + + assertThat(roundtrippedScoreSummary).isEqualTo(scoreSummary) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ScorerTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ScorerTest.kt deleted file mode 100644 index 3c30d63c..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ScorerTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class ScorerTest { - - @Test - fun createScorer() { - val scorer = Scorer.builder().index(123L).type(Scorer.Type.SCORER).build() - assertThat(scorer).isNotNull - assertThat(scorer.index()).isEqualTo(123L) - assertThat(scorer.type()).isEqualTo(Scorer.Type.SCORER) - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanAttributesTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanAttributesTest.kt new file mode 100644 index 00000000..644f7949 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanAttributesTest.kt @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.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 SpanAttributesTest { + + @Test + fun create() { + val spanAttributes = SpanAttributes.builder().name("name").type(SpanType.LLM).build() + + assertThat(spanAttributes.name()).isEqualTo("name") + assertThat(spanAttributes.type()).isEqualTo(SpanType.LLM) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val spanAttributes = SpanAttributes.builder().name("name").type(SpanType.LLM).build() + + val roundtrippedSpanAttributes = + jsonMapper.readValue( + jsonMapper.writeValueAsString(spanAttributes), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSpanAttributes).isEqualTo(spanAttributes) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIFrameTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIFrameTest.kt new file mode 100644 index 00000000..068e3129 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIFrameTest.kt @@ -0,0 +1,64 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIFrameTest { + + @Test + fun create() { + val spanIFrame = + SpanIFrame.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .postMessage(true) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + assertThat(spanIFrame.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(spanIFrame.name()).isEqualTo("name") + assertThat(spanIFrame.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(spanIFrame.url()).isEqualTo("url") + assertThat(spanIFrame.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + assertThat(spanIFrame.deletedAt()) + .isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + assertThat(spanIFrame.description()).isEqualTo("description") + assertThat(spanIFrame.postMessage()).isEqualTo(true) + assertThat(spanIFrame.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val spanIFrame = + SpanIFrame.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .postMessage(true) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedSpanIFrame = + jsonMapper.readValue( + jsonMapper.writeValueAsString(spanIFrame), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSpanIFrame).isEqualTo(spanIFrame) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeCreateParamsTest.kt new file mode 100644 index 00000000..70151bf2 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeCreateParamsTest.kt @@ -0,0 +1,56 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIframeCreateParamsTest { + + @Test + fun create() { + SpanIframeCreateParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + } + + @Test + fun body() { + val params = + SpanIframeCreateParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("name") + assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.url()).isEqualTo("url") + assertThat(body.description()).isEqualTo("description") + assertThat(body.postMessage()).isEqualTo(true) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SpanIframeCreateParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("name") + assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.url()).isEqualTo("url") + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeDeleteParamsTest.kt new file mode 100644 index 00000000..09ce2983 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeDeleteParamsTest.kt @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIframeDeleteParamsTest { + + @Test + fun create() { + SpanIframeDeleteParams.builder() + .spanIframeId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + } + + @Test + fun pathParams() { + val params = + SpanIframeDeleteParams.builder() + .spanIframeId("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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeListPageResponseTest.kt new file mode 100644 index 00000000..86a3f694 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeListPageResponseTest.kt @@ -0,0 +1,76 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIframeListPageResponseTest { + + @Test + fun create() { + val spanIframeListPageResponse = + SpanIframeListPageResponse.builder() + .addObject( + SpanIFrame.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .postMessage(true) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + assertThat(spanIframeListPageResponse.objects()) + .containsExactly( + SpanIFrame.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .postMessage(true) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val spanIframeListPageResponse = + SpanIframeListPageResponse.builder() + .addObject( + SpanIFrame.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .description("description") + .postMessage(true) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedSpanIframeListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(spanIframeListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSpanIframeListPageResponse).isEqualTo(spanIframeListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeListParamsTest.kt new file mode 100644 index 00000000..47aed4d6 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeListParamsTest.kt @@ -0,0 +1,58 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.http.QueryParams +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIframeListParamsTest { + + @Test + fun create() { + SpanIframeListParams.builder() + .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .orgName("org_name") + .spanIframeName("span_iframe_name") + .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + } + + @Test + fun queryParams() { + val params = + SpanIframeListParams.builder() + .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .orgName("org_name") + .spanIframeName("span_iframe_name") + .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("span_iframe_name", "span_iframe_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + } + + @Test + fun queryParamsWithoutOptionalFields() { + val params = SpanIframeListParams.builder().build() + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeReplaceParamsTest.kt new file mode 100644 index 00000000..12971a84 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeReplaceParamsTest.kt @@ -0,0 +1,56 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIframeReplaceParamsTest { + + @Test + fun create() { + SpanIframeReplaceParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + } + + @Test + fun body() { + val params = + SpanIframeReplaceParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("name") + assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.url()).isEqualTo("url") + assertThat(body.description()).isEqualTo("description") + assertThat(body.postMessage()).isEqualTo(true) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SpanIframeReplaceParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .build() + + val body = params._body() + + assertThat(body.name()).isEqualTo("name") + assertThat(body.projectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.url()).isEqualTo("url") + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeRetrieveParamsTest.kt new file mode 100644 index 00000000..885d2d46 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeRetrieveParamsTest.kt @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIframeRetrieveParamsTest { + + @Test + fun create() { + SpanIframeRetrieveParams.builder() + .spanIframeId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + } + + @Test + fun pathParams() { + val params = + SpanIframeRetrieveParams.builder() + .spanIframeId("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/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeUpdateParamsTest.kt new file mode 100644 index 00000000..460a9fc2 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SpanIframeUpdateParamsTest.kt @@ -0,0 +1,61 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SpanIframeUpdateParamsTest { + + @Test + fun create() { + SpanIframeUpdateParams.builder() + .spanIframeId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .name("name") + .postMessage(true) + .url("url") + .build() + } + + @Test + fun pathParams() { + val params = + SpanIframeUpdateParams.builder() + .spanIframeId("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 body() { + val params = + SpanIframeUpdateParams.builder() + .spanIframeId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .name("name") + .postMessage(true) + .url("url") + .build() + + val body = params._body() + + assertThat(body.description()).isEqualTo("description") + assertThat(body.name()).isEqualTo("name") + assertThat(body.postMessage()).isEqualTo(true) + assertThat(body.url()).isEqualTo("url") + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SpanIframeUpdateParams.builder() + .spanIframeId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val body = params._body() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponseTest.kt index fb1ee33d..c083f0bf 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeDatasetResponseTest.kt @@ -2,27 +2,50 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class SummarizeDatasetResponseTest { +internal class SummarizeDatasetResponseTest { @Test - fun createSummarizeDatasetResponse() { + fun create() { val summarizeDatasetResponse = SummarizeDatasetResponse.builder() .datasetName("dataset_name") .datasetUrl("https://example.com") .projectName("project_name") .projectUrl("https://example.com") - .dataSummary(DataSummary.builder().totalRecords(123L).build()) + .dataSummary(DataSummary.builder().totalRecords(0L).build()) .build() - assertThat(summarizeDatasetResponse).isNotNull + assertThat(summarizeDatasetResponse.datasetName()).isEqualTo("dataset_name") assertThat(summarizeDatasetResponse.datasetUrl()).isEqualTo("https://example.com") assertThat(summarizeDatasetResponse.projectName()).isEqualTo("project_name") assertThat(summarizeDatasetResponse.projectUrl()).isEqualTo("https://example.com") assertThat(summarizeDatasetResponse.dataSummary()) - .isEqualTo(DataSummary.builder().totalRecords(123L).build()) + .isEqualTo(DataSummary.builder().totalRecords(0L).build()) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val summarizeDatasetResponse = + SummarizeDatasetResponse.builder() + .datasetName("dataset_name") + .datasetUrl("https://example.com") + .projectName("project_name") + .projectUrl("https://example.com") + .dataSummary(DataSummary.builder().totalRecords(0L).build()) + .build() + + val roundtrippedSummarizeDatasetResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(summarizeDatasetResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSummarizeDatasetResponse).isEqualTo(summarizeDatasetResponse) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponseTest.kt index a26cf800..82b8415c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponseTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/SummarizeExperimentResponseTest.kt @@ -2,13 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class SummarizeExperimentResponseTest { +internal class SummarizeExperimentResponseTest { @Test - fun createSummarizeExperimentResponse() { + fun create() { val summarizeExperimentResponse = SummarizeExperimentResponse.builder() .experimentName("experiment_name") @@ -16,10 +19,41 @@ class SummarizeExperimentResponseTest { .projectName("project_name") .projectUrl("https://example.com") .comparisonExperimentName("comparison_experiment_name") - .metrics(SummarizeExperimentResponse.Metrics.builder().build()) - .scores(SummarizeExperimentResponse.Scores.builder().build()) + .metrics( + SummarizeExperimentResponse.Metrics.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "improvements" to 0, + "metric" to 0, + "name" to "name", + "regressions" to 0, + "unit" to "unit", + "diff" to 0, + ) + ), + ) + .build() + ) + .scores( + SummarizeExperimentResponse.Scores.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "improvements" to 0, + "name" to "name", + "regressions" to 0, + "score" to 0, + "diff" to -1, + ) + ), + ) + .build() + ) .build() - assertThat(summarizeExperimentResponse).isNotNull + assertThat(summarizeExperimentResponse.experimentName()).isEqualTo("experiment_name") assertThat(summarizeExperimentResponse.experimentUrl()).isEqualTo("https://example.com") assertThat(summarizeExperimentResponse.projectName()).isEqualTo("project_name") @@ -27,8 +61,93 @@ class SummarizeExperimentResponseTest { assertThat(summarizeExperimentResponse.comparisonExperimentName()) .isEqualTo("comparison_experiment_name") assertThat(summarizeExperimentResponse.metrics()) - .isEqualTo(SummarizeExperimentResponse.Metrics.builder().build()) + .isEqualTo( + SummarizeExperimentResponse.Metrics.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "improvements" to 0, + "metric" to 0, + "name" to "name", + "regressions" to 0, + "unit" to "unit", + "diff" to 0, + ) + ), + ) + .build() + ) assertThat(summarizeExperimentResponse.scores()) - .isEqualTo(SummarizeExperimentResponse.Scores.builder().build()) + .isEqualTo( + SummarizeExperimentResponse.Scores.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "improvements" to 0, + "name" to "name", + "regressions" to 0, + "score" to 0, + "diff" to -1, + ) + ), + ) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val summarizeExperimentResponse = + SummarizeExperimentResponse.builder() + .experimentName("experiment_name") + .experimentUrl("https://example.com") + .projectName("project_name") + .projectUrl("https://example.com") + .comparisonExperimentName("comparison_experiment_name") + .metrics( + SummarizeExperimentResponse.Metrics.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "improvements" to 0, + "metric" to 0, + "name" to "name", + "regressions" to 0, + "unit" to "unit", + "diff" to 0, + ) + ), + ) + .build() + ) + .scores( + SummarizeExperimentResponse.Scores.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "improvements" to 0, + "name" to "name", + "regressions" to 0, + "score" to 0, + "diff" to -1, + ) + ), + ) + .build() + ) + .build() + + val roundtrippedSummarizeExperimentResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(summarizeExperimentResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSummarizeExperimentResponse).isEqualTo(summarizeExperimentResponse) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/TaskTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/TaskTest.kt deleted file mode 100644 index c8ec14d7..00000000 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/TaskTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.braintrustdata.api.models - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class TaskTest { - - @Test - fun createTask() { - val task = Task.builder().type(Task.Type.TASK).build() - assertThat(task).isNotNull - assertThat(task.type()).isEqualTo(Task.Type.TASK) - } -} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParamsTest.kt index b059ced3..fa29626f 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/TopLevelHelloWorldParamsTest.kt @@ -2,13 +2,12 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.junit.jupiter.api.Test -class TopLevelHelloWorldParamsTest { +internal class TopLevelHelloWorldParamsTest { @Test - fun createTopLevelHelloWorldParams() { + fun create() { TopLevelHelloWorldParams.builder().build() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserListPageResponseTest.kt new file mode 100644 index 00000000..58f9ef44 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserListPageResponseTest.kt @@ -0,0 +1,67 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class UserListPageResponseTest { + + @Test + fun create() { + val userListPageResponse = + UserListPageResponse.builder() + .addObject( + User.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .avatarUrl("avatar_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .email("email") + .familyName("family_name") + .givenName("given_name") + .build() + ) + .build() + + assertThat(userListPageResponse.objects()) + .containsExactly( + User.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .avatarUrl("avatar_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .email("email") + .familyName("family_name") + .givenName("given_name") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val userListPageResponse = + UserListPageResponse.builder() + .addObject( + User.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .avatarUrl("avatar_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .email("email") + .familyName("family_name") + .givenName("given_name") + .build() + ) + .build() + + val roundtrippedUserListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(userListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedUserListPageResponse).isEqualTo(userListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserListParamsTest.kt index 45d5d6ce..59ea68cd 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserListParamsTest.kt @@ -2,58 +2,63 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class UserListParamsTest { +internal class UserListParamsTest { @Test - fun createUserListParams() { + fun create() { UserListParams.builder() - .email(UserListParams.Email.ofString("string")) + .email("string") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .familyName(UserListParams.FamilyName.ofString("string")) - .givenName(UserListParams.GivenName.ofString("string")) - .ids(UserListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .familyName("string") + .givenName("string") + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = UserListParams.builder() - .email(UserListParams.Email.ofString("string")) + .email("string") .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .familyName(UserListParams.FamilyName.ofString("string")) - .givenName(UserListParams.GivenName.ofString("string")) - .ids(UserListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .familyName("string") + .givenName("string") + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .orgName("org_name") .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() - val expected = mutableMapOf>() - expected.put("email", listOf(UserListParams.Email.ofString("string").toString())) - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("family_name", listOf(UserListParams.FamilyName.ofString("string").toString())) - expected.put("given_name", listOf(UserListParams.GivenName.ofString("string").toString())) - expected.put( - "ids", - listOf(UserListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("org_name", listOf("org_name")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("email", "string") + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("family_name", "string") + .put("given_name", "string") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("org_name", "org_name") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = UserListParams.builder().build() - val expected = mutableMapOf>() - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserRetrieveParamsTest.kt index ee03a0d3..f684fdad 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserRetrieveParamsTest.kt @@ -2,25 +2,23 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class UserRetrieveParamsTest { +internal class UserRetrieveParamsTest { @Test - fun createUserRetrieveParams() { + fun create() { UserRetrieveParams.builder().userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() } @Test - fun getPathParam() { + fun pathParams() { val params = UserRetrieveParams.builder().userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - assertThat(params).isNotNull - // path param "userId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserTest.kt index f7c71792..0deb054c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/UserTest.kt @@ -2,14 +2,16 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class UserTest { +internal class UserTest { @Test - fun createUser() { + fun create() { val user = User.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -19,7 +21,7 @@ class UserTest { .familyName("family_name") .givenName("given_name") .build() - assertThat(user).isNotNull + assertThat(user.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(user.avatarUrl()).isEqualTo("avatar_url") assertThat(user.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) @@ -27,4 +29,23 @@ class UserTest { assertThat(user.familyName()).isEqualTo("family_name") assertThat(user.givenName()).isEqualTo("given_name") } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val user = + User.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .avatarUrl("avatar_url") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .email("email") + .familyName("family_name") + .givenName("given_name") + .build() + + val roundtrippedUser = + jsonMapper.readValue(jsonMapper.writeValueAsString(user), jacksonTypeRef()) + + assertThat(roundtrippedUser).isEqualTo(user) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewCreateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewCreateParamsTest.kt index 931b25d4..917f2ce2 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewCreateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewCreateParamsTest.kt @@ -2,27 +2,37 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewCreateParamsTest { +internal class ViewCreateParamsTest { @Test - fun createViewCreateParams() { + fun create() { ViewCreateParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .viewType(ViewCreateParams.ViewType.PROJECTS) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -30,10 +40,10 @@ class ViewCreateParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() @@ -42,19 +52,30 @@ class ViewCreateParamsTest { } @Test - fun getBody() { + fun body() { val params = ViewCreateParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .viewType(ViewCreateParams.ViewType.PROJECTS) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -62,28 +83,40 @@ class ViewCreateParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewCreateParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(body.viewType()).isEqualTo(ViewCreateParams.ViewType.PROJECTS) assertThat(body.deletedAt()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(body.options()) .isEqualTo( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) assertThat(body.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -92,10 +125,10 @@ class ViewCreateParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() @@ -103,17 +136,20 @@ class ViewCreateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ViewCreateParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) + .viewType(ViewCreateParams.ViewType.PROJECTS) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewCreateParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) + assertThat(body.viewType()).isEqualTo(ViewCreateParams.ViewType.PROJECTS) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataSearchTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataSearchTest.kt index 40471c67..2c03aaf7 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataSearchTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataSearchTest.kt @@ -2,25 +2,47 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewDataSearchTest { +internal class ViewDataSearchTest { @Test - fun createViewDataSearch() { + fun create() { val viewDataSearch = ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() - assertThat(viewDataSearch).isNotNull - assertThat(viewDataSearch.filter()).containsExactly(JsonNull.of()) - assertThat(viewDataSearch.match()).containsExactly(JsonNull.of()) - assertThat(viewDataSearch.sort()).containsExactly(JsonNull.of()) - assertThat(viewDataSearch.tag()).containsExactly(JsonNull.of()) + + assertThat(viewDataSearch.filter()).containsExactly(JsonValue.from(mapOf())) + assertThat(viewDataSearch.match()).containsExactly(JsonValue.from(mapOf())) + assertThat(viewDataSearch.sort()).containsExactly(JsonValue.from(mapOf())) + assertThat(viewDataSearch.tag()).containsExactly(JsonValue.from(mapOf())) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val viewDataSearch = + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + + val roundtrippedViewDataSearch = + jsonMapper.readValue( + jsonMapper.writeValueAsString(viewDataSearch), + jacksonTypeRef(), + ) + + assertThat(roundtrippedViewDataSearch).isEqualTo(viewDataSearch) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataTest.kt index 0ebf05b4..f92b2c47 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDataTest.kt @@ -2,34 +2,60 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewDataTest { +internal class ViewDataTest { @Test - fun createViewData() { + fun create() { val viewData = ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() - assertThat(viewData).isNotNull + assertThat(viewData.search()) .isEqualTo( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val viewData = + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + + val roundtrippedViewData = + jsonMapper.readValue( + jsonMapper.writeValueAsString(viewData), + jacksonTypeRef(), + ) + + assertThat(roundtrippedViewData).isEqualTo(viewData) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDeleteParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDeleteParamsTest.kt index 76883050..e6224941 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDeleteParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewDeleteParamsTest.kt @@ -2,61 +2,46 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewDeleteParamsTest { +internal class ViewDeleteParamsTest { @Test - fun createViewDeleteParams() { + fun create() { ViewDeleteParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() } @Test - fun getBody() { + fun pathParams() { val params = ViewDeleteParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewDeleteParams.ObjectType.ORGANIZATION) - } - @Test - fun getBodyWithoutOptionalFields() { - val params = - ViewDeleteParams.builder() - .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewDeleteParams.ObjectType.ORGANIZATION) - .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewDeleteParams.ObjectType.ORGANIZATION) + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getPathParam() { + fun body() { val params = ViewDeleteParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - assertThat(params).isNotNull - // path param "viewId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val body = params._body() + + assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewListPageResponseTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewListPageResponseTest.kt new file mode 100644 index 00000000..9f6575f0 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewListPageResponseTest.kt @@ -0,0 +1,164 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.models + +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ViewListPageResponseTest { + + @Test + fun create() { + val viewListPageResponse = + ViewListPageResponse.builder() + .addObject( + View.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .viewType(View.ViewType.PROJECTS) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .options( + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .viewData( + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + ) + .build() + ) + .build() + + assertThat(viewListPageResponse.objects()) + .containsExactly( + View.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .viewType(View.ViewType.PROJECTS) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .options( + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .viewData( + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + ) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val viewListPageResponse = + ViewListPageResponse.builder() + .addObject( + View.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .viewType(View.ViewType.PROJECTS) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .options( + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .viewData( + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + ) + .build() + ) + .build() + + val roundtrippedViewListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(viewListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedViewListPageResponse).isEqualTo(viewListPageResponse) + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewListParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewListParamsTest.kt index 5b3094b1..05c283a8 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewListParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewListParamsTest.kt @@ -2,64 +2,73 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewListParamsTest { +internal class ViewListParamsTest { @Test - fun createViewListParams() { + fun create() { ViewListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ViewListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .viewName("view_name") - .viewType(ViewListParams.ViewType.PROJECTS) + .viewType(ViewType.PROJECTS) .build() } @Test - fun getQueryParams() { + fun queryParams() { val params = ViewListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .endingBefore("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .ids(ViewListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .startingAfter("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .viewName("view_name") - .viewType(ViewListParams.ViewType.PROJECTS) + .viewType(ViewType.PROJECTS) .build() - val expected = mutableMapOf>() - expected.put("object_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("object_type", listOf(ViewListParams.ObjectType.ORGANIZATION.toString())) - expected.put("ending_before", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put( - "ids", - listOf(ViewListParams.Ids.ofString("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").toString()) - ) - expected.put("limit", listOf("123")) - expected.put("starting_after", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("view_name", listOf("view_name")) - expected.put("view_type", listOf(ViewListParams.ViewType.PROJECTS.toString())) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("object_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("object_type", "organization") + .put("ending_before", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("ids", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("limit", "0") + .put("starting_after", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("view_name", "view_name") + .put("view_type", "projects") + .build() + ) } @Test - fun getQueryParamsWithoutOptionalFields() { + fun queryParamsWithoutOptionalFields() { val params = ViewListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - val expected = mutableMapOf>() - expected.put("object_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("object_type", listOf(ViewListParams.ObjectType.ORGANIZATION.toString())) - assertThat(params.getQueryParams()).isEqualTo(expected) + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("object_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("object_type", "organization") + .build() + ) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewOptionsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewOptionsTest.kt index 8287a9b4..26116ff3 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewOptionsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewOptionsTest.kt @@ -2,23 +2,79 @@ package com.braintrustdata.api.models +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewOptionsTest { +internal class ViewOptionsTest { @Test - fun createViewOptions() { + fun create() { val viewOptions = ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() - assertThat(viewOptions).isNotNull + assertThat(viewOptions.columnOrder()).containsExactly("string") - assertThat(viewOptions.columnSizing()).isEqualTo(ViewOptions.ColumnSizing.builder().build()) + assertThat(viewOptions.columnSizing()) + .isEqualTo( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) assertThat(viewOptions.columnVisibility()) - .isEqualTo(ViewOptions.ColumnVisibility.builder().build()) + .isEqualTo( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + assertThat(viewOptions.grouping()).isEqualTo("grouping") + assertThat(viewOptions.layout()).isEqualTo("layout") + assertThat(viewOptions.rowHeight()).isEqualTo("rowHeight") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val viewOptions = + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + + val roundtrippedViewOptions = + jsonMapper.readValue( + jsonMapper.writeValueAsString(viewOptions), + jacksonTypeRef(), + ) + + assertThat(roundtrippedViewOptions).isEqualTo(viewOptions) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewReplaceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewReplaceParamsTest.kt index 6162d192..b4801f2d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewReplaceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewReplaceParamsTest.kt @@ -2,27 +2,37 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewReplaceParamsTest { +internal class ViewReplaceParamsTest { @Test - fun createViewReplaceParams() { + fun create() { ViewReplaceParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewReplaceParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .viewType(ViewReplaceParams.ViewType.PROJECTS) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -30,10 +40,10 @@ class ViewReplaceParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() @@ -42,19 +52,30 @@ class ViewReplaceParamsTest { } @Test - fun getBody() { + fun body() { val params = ViewReplaceParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewReplaceParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .viewType(ViewReplaceParams.ViewType.PROJECTS) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -62,28 +83,40 @@ class ViewReplaceParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() ) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewReplaceParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(body.viewType()).isEqualTo(ViewReplaceParams.ViewType.PROJECTS) assertThat(body.deletedAt()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(body.options()) .isEqualTo( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) assertThat(body.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -92,10 +125,10 @@ class ViewReplaceParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() @@ -103,17 +136,20 @@ class ViewReplaceParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ViewReplaceParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewReplaceParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) + .viewType(ViewReplaceParams.ViewType.PROJECTS) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.name()).isEqualTo("name") assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewReplaceParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) + assertThat(body.viewType()).isEqualTo(ViewReplaceParams.ViewType.PROJECTS) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewRetrieveParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewRetrieveParamsTest.kt index c381863a..84cc78de 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewRetrieveParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewRetrieveParamsTest.kt @@ -2,61 +2,52 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewRetrieveParamsTest { +internal class ViewRetrieveParamsTest { @Test - fun createViewRetrieveParams() { + fun create() { ViewRetrieveParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewRetrieveParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() } @Test - fun getQueryParams() { + fun pathParams() { val params = ViewRetrieveParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewRetrieveParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - val expected = mutableMapOf>() - expected.put("object_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("object_type", listOf(ViewRetrieveParams.ObjectType.ORGANIZATION.toString())) - assertThat(params.getQueryParams()).isEqualTo(expected) - } - @Test - fun getQueryParamsWithoutOptionalFields() { - val params = - ViewRetrieveParams.builder() - .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewRetrieveParams.ObjectType.ORGANIZATION) - .build() - val expected = mutableMapOf>() - expected.put("object_id", listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - expected.put("object_type", listOf(ViewRetrieveParams.ObjectType.ORGANIZATION.toString())) - assertThat(params.getQueryParams()).isEqualTo(expected) + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") } @Test - fun getPathParam() { + fun queryParams() { val params = ViewRetrieveParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewRetrieveParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - assertThat(params).isNotNull - // path param "viewId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("object_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .put("object_type", "organization") + .build() + ) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewTest.kt index d98e9cb7..ba50f8dd 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewTest.kt @@ -2,29 +2,42 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewTest { +internal class ViewTest { @Test - fun createView() { + fun create() { val view = View.builder() .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(View.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .viewType(View.ViewType.PROJECTS) .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -32,29 +45,40 @@ class ViewTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() ) .build() - assertThat(view).isNotNull + assertThat(view.id()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") assertThat(view.name()).isEqualTo("name") assertThat(view.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(view.objectType()).isEqualTo(View.ObjectType.ORGANIZATION) + assertThat(view.objectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(view.viewType()).isEqualTo(View.ViewType.PROJECTS) assertThat(view.created()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(view.deletedAt()).isEqualTo(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) assertThat(view.options()) .isEqualTo( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) assertThat(view.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -63,13 +87,64 @@ class ViewTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() ) } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val view = + View.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .viewType(View.ViewType.PROJECTS) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .options( + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .viewData( + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + ) + .build() + + val roundtrippedView = + jsonMapper.readValue(jsonMapper.writeValueAsString(view), jacksonTypeRef()) + + assertThat(roundtrippedView).isEqualTo(view) + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewUpdateParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewUpdateParamsTest.kt index bfed15c2..a6a499ff 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewUpdateParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/models/ViewUpdateParamsTest.kt @@ -2,25 +2,35 @@ package com.braintrustdata.api.models -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -class ViewUpdateParamsTest { +internal class ViewUpdateParamsTest { @Test - fun createViewUpdateParams() { + fun create() { ViewUpdateParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewUpdateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .name("name") .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -28,10 +38,10 @@ class ViewUpdateParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() @@ -41,18 +51,43 @@ class ViewUpdateParamsTest { } @Test - fun getBody() { + fun pathParams() { + val params = + ViewUpdateParams.builder() + .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun body() { val params = ViewUpdateParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewUpdateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .name("name") .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -60,27 +95,39 @@ class ViewUpdateParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() ) .viewType(ViewUpdateParams.ViewType.PROJECTS) .build() - val body = params.getBody() - assertThat(body).isNotNull + + val body = params._body() + assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewUpdateParams.ObjectType.ORGANIZATION) + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) assertThat(body.name()).isEqualTo("name") assertThat(body.options()) .isEqualTo( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) assertThat(body.userId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -89,10 +136,10 @@ class ViewUpdateParamsTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() @@ -101,31 +148,17 @@ class ViewUpdateParamsTest { } @Test - fun getBodyWithoutOptionalFields() { + fun bodyWithoutOptionalFields() { val params = ViewUpdateParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewUpdateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() - val body = params.getBody() - assertThat(body).isNotNull - assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - assertThat(body.objectType()).isEqualTo(ViewUpdateParams.ObjectType.ORGANIZATION) - } - @Test - fun getPathParam() { - val params = - ViewUpdateParams.builder() - .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewUpdateParams.ObjectType.ORGANIZATION) - .build() - assertThat(params).isNotNull - // path param "viewId" - assertThat(params.getPathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params.getPathParam(1)).isEqualTo("") + val body = params._body() + + assertThat(body.objectId()).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + assertThat(body.objectType()).isEqualTo(AclObjectType.ORGANIZATION) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ErrorHandlingTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ErrorHandlingTest.kt index 58a2b8f5..7be04bf5 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ErrorHandlingTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ErrorHandlingTest.kt @@ -4,10 +4,10 @@ package com.braintrustdata.api.services import com.braintrustdata.api.client.BraintrustClient import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.core.JsonString +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.core.http.Headers import com.braintrustdata.api.core.jsonMapper import com.braintrustdata.api.errors.BadRequestException -import com.braintrustdata.api.errors.BraintrustError import com.braintrustdata.api.errors.BraintrustException import com.braintrustdata.api.errors.InternalServerException import com.braintrustdata.api.errors.NotFoundException @@ -16,33 +16,36 @@ import com.braintrustdata.api.errors.RateLimitException import com.braintrustdata.api.errors.UnauthorizedException import com.braintrustdata.api.errors.UnexpectedStatusCodeException import com.braintrustdata.api.errors.UnprocessableEntityException -import com.braintrustdata.api.models.* -import com.fasterxml.jackson.databind.json.JsonMapper +import com.braintrustdata.api.models.ProjectCreateParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl -import com.github.tomakehurst.wiremock.client.WireMock.get -import com.github.tomakehurst.wiremock.client.WireMock.ok 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.google.common.collect.ImmutableListMultimap -import com.google.common.collect.ListMultimap -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatThrownBy -import org.assertj.core.api.InstanceOfAssertFactories -import org.assertj.guava.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 -class ErrorHandlingTest { +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class ErrorHandlingTest { - private val JSON_MAPPER: JsonMapper = jsonMapper() + companion object { - private val BRAINTRUST_ERROR: BraintrustError = - BraintrustError.builder().putAdditionalProperty("key", JsonString.of("value")).build() + 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: BraintrustClient @@ -50,306 +53,383 @@ class ErrorHandlingTest { fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { client = BraintrustOkHttpClient.builder() - .baseUrl(wmRuntimeInfo.getHttpBaseUrl()) + .baseUrl(wmRuntimeInfo.httpBaseUrl) .apiKey("My API Key") .build() } @Test - fun projectsCreate200() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() - - val expected = - Project.builder() - .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .name("name") - .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .settings(ProjectSettings.builder().comparisonKey("comparison_key").build()) - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() + fun projectsCreate400() { + val projectService = client.projects() + stubFor( + post(anyUrl()) + .willReturn( + status(400).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) - stubFor(post(anyUrl()).willReturn(ok().withBody(toJson(expected)))) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").build() + ) + } - assertThat(client.projects().create(params)).isEqualTo(expected) + assertThat(e.statusCode()).isEqualTo(400) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) } @Test - fun projectsCreate400() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() - + fun projectsCreate400WithRawResponse() { + val projectService = client.projects().withRawResponse() stubFor( post(anyUrl()) - .willReturn(status(400).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(400).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertBadRequest(e, ImmutableListMultimap.of("Foo", "Bar"), BRAINTRUST_ERROR) - }) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate401() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() + val projectService = client.projects() + stubFor( + post(anyUrl()) + .willReturn( + status(401).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate401WithRawResponse() { + val projectService = client.projects().withRawResponse() stubFor( post(anyUrl()) - .willReturn(status(401).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(401).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertUnauthorized(e, ImmutableListMultimap.of("Foo", "Bar"), BRAINTRUST_ERROR) - }) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate403() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() + val projectService = client.projects() + stubFor( + post(anyUrl()) + .willReturn( + status(403).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate403WithRawResponse() { + val projectService = client.projects().withRawResponse() stubFor( post(anyUrl()) - .willReturn(status(403).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(403).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertPermissionDenied(e, ImmutableListMultimap.of("Foo", "Bar"), BRAINTRUST_ERROR) - }) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate404() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() + val projectService = client.projects() + stubFor( + post(anyUrl()) + .willReturn( + status(404).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate404WithRawResponse() { + val projectService = client.projects().withRawResponse() stubFor( post(anyUrl()) - .willReturn(status(404).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(404).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertNotFound(e, ImmutableListMultimap.of("Foo", "Bar"), BRAINTRUST_ERROR) - }) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate422() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() - + val projectService = client.projects() stubFor( post(anyUrl()) - .willReturn(status(422).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(422).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertUnprocessableEntity( - e, - ImmutableListMultimap.of("Foo", "Bar"), - BRAINTRUST_ERROR + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate429() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() - + fun projectsCreate422WithRawResponse() { + val projectService = client.projects().withRawResponse() stubFor( post(anyUrl()) - .willReturn(status(429).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(422).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertRateLimit(e, ImmutableListMultimap.of("Foo", "Bar"), BRAINTRUST_ERROR) - }) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 projectsCreate500() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() - + fun projectsCreate429() { + val projectService = client.projects() stubFor( post(anyUrl()) - .willReturn(status(500).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(429).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertInternalServer(e, ImmutableListMultimap.of("Foo", "Bar"), BRAINTRUST_ERROR) - }) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 unexpectedStatusCode() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() - + fun projectsCreate429WithRawResponse() { + val projectService = client.projects().withRawResponse() stubFor( post(anyUrl()) - .willReturn(status(999).withHeader("Foo", "Bar").withBody(toJson(BRAINTRUST_ERROR))) + .willReturn( + status(429).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) ) - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertUnexpectedStatusCodeException( - e, - 999, - ImmutableListMultimap.of("Foo", "Bar"), - toJson(BRAINTRUST_ERROR) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").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 invalidBody() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() + fun projectsCreate500() { + val projectService = client.projects() + stubFor( + post(anyUrl()) + .willReturn( + status(500).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) - stubFor(post(anyUrl()).willReturn(status(200).withBody("Not JSON"))) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").build() + ) + } - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertThat(e) - .isInstanceOf(BraintrustException::class.java) - .hasMessage("Error reading response") - }) + assertThat(e.statusCode()).isEqualTo(500) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) } @Test - fun invalidErrorBody() { - val params = ProjectCreateParams.builder().name("name").orgName("org_name").build() + fun projectsCreate500WithRawResponse() { + val projectService = client.projects().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(500).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) - stubFor(post(anyUrl()).willReturn(status(400).withBody("Not JSON"))) + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").build() + ) + } - assertThatThrownBy({ client.projects().create(params) }) - .satisfies({ e -> - assertBadRequest(e, ImmutableListMultimap.of(), BraintrustError.builder().build()) - }) + assertThat(e.statusCode()).isEqualTo(500) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) } - private fun toJson(body: T): ByteArray { - return JSON_MAPPER.writeValueAsBytes(body) - } + @Test + fun projectsCreate999() { + val projectService = client.projects() + stubFor( + post(anyUrl()) + .willReturn( + status(999).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) - private fun assertUnexpectedStatusCodeException( - throwable: Throwable, - statusCode: Int, - headers: ListMultimap, - responseBody: ByteArray - ) { - assertThat(throwable) - .asInstanceOf( - InstanceOfAssertFactories.throwable(UnexpectedStatusCodeException::class.java) - ) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(statusCode) - assertThat(e.body()).isEqualTo(String(responseBody)) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) - } + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").build() + ) + } - private fun assertBadRequest( - throwable: Throwable, - headers: ListMultimap, - error: BraintrustError - ) { - assertThat(throwable) - .asInstanceOf(InstanceOfAssertFactories.throwable(BadRequestException::class.java)) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(400) - assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) + assertThat(e.statusCode()).isEqualTo(999) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) } - private fun assertUnauthorized( - throwable: Throwable, - headers: ListMultimap, - error: BraintrustError - ) { - assertThat(throwable) - .asInstanceOf(InstanceOfAssertFactories.throwable(UnauthorizedException::class.java)) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(401) - assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) - } + @Test + fun projectsCreate999WithRawResponse() { + val projectService = client.projects().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(999).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) - private fun assertPermissionDenied( - throwable: Throwable, - headers: ListMultimap, - error: BraintrustError - ) { - assertThat(throwable) - .asInstanceOf( - InstanceOfAssertFactories.throwable(PermissionDeniedException::class.java) - ) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(403) - assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) - } + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").build() + ) + } - private fun assertNotFound( - throwable: Throwable, - headers: ListMultimap, - error: BraintrustError - ) { - assertThat(throwable) - .asInstanceOf(InstanceOfAssertFactories.throwable(NotFoundException::class.java)) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(404) - assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) + assertThat(e.statusCode()).isEqualTo(999) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) } - private fun assertUnprocessableEntity( - throwable: Throwable, - headers: ListMultimap, - error: BraintrustError - ) { - assertThat(throwable) - .asInstanceOf( - InstanceOfAssertFactories.throwable(UnprocessableEntityException::class.java) - ) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(422) - assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) - } + @Test + fun projectsCreateInvalidJsonBody() { + val projectService = client.projects() + stubFor( + post(anyUrl()) + .willReturn(status(200).withHeader(HEADER_NAME, HEADER_VALUE).withBody(NOT_JSON)) + ) - private fun assertRateLimit( - throwable: Throwable, - headers: ListMultimap, - error: BraintrustError - ) { - assertThat(throwable) - .asInstanceOf(InstanceOfAssertFactories.throwable(RateLimitException::class.java)) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(429) - assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) - } + val e = + assertThrows { + projectService.create( + ProjectCreateParams.builder().name("x").orgName("org_name").build() + ) + } - private fun assertInternalServer( - throwable: Throwable, - headers: ListMultimap, - error: BraintrustError - ) { - assertThat(throwable) - .asInstanceOf(InstanceOfAssertFactories.throwable(InternalServerException::class.java)) - .satisfies({ e -> - assertThat(e.statusCode()).isEqualTo(500) - assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) - }) + assertThat(e).hasMessage("Error reading response") } + + private fun Headers.toMap(): Map> = + mutableMapOf>().also { map -> + names().forEach { map[it] = values(it) } + } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ServiceParamsTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ServiceParamsTest.kt index d1c75949..436926c8 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ServiceParamsTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/ServiceParamsTest.kt @@ -4,31 +4,25 @@ package com.braintrustdata.api.services import com.braintrustdata.api.client.BraintrustClient import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.core.JsonString import com.braintrustdata.api.core.JsonValue -import com.braintrustdata.api.core.jsonMapper -import com.braintrustdata.api.models.* -import com.fasterxml.jackson.databind.json.JsonMapper +import com.braintrustdata.api.models.ProjectCreateParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.equalTo -import com.github.tomakehurst.wiremock.client.WireMock.get 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.put 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.Test +import org.junit.jupiter.api.parallel.ResourceLock @WireMockTest -class ServiceParamsTest { - - private val JSON_MAPPER: JsonMapper = jsonMapper() +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class ServiceParamsTest { private lateinit var client: BraintrustClient @@ -36,55 +30,31 @@ class ServiceParamsTest { fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { client = BraintrustOkHttpClient.builder() + .baseUrl(wmRuntimeInfo.httpBaseUrl) .apiKey("My API Key") - .baseUrl(wmRuntimeInfo.getHttpBaseUrl()) .build() } @Test - fun projectsCreateWithAdditionalParams() { - val additionalHeaders = mutableMapOf>() - - additionalHeaders.put("x-test-header", listOf("abc1234")) - - val additionalQueryParams = mutableMapOf>() - - additionalQueryParams.put("test_query_param", listOf("def567")) - - val additionalBodyProperties = mutableMapOf() - - additionalBodyProperties.put("testBodyProperty", JsonString.of("ghi890")) + fun create() { + val projectService = client.projects() + stubFor(post(anyUrl()).willReturn(ok("{}"))) - val params = + projectService.create( ProjectCreateParams.builder() - .name("name") + .name("x") .orgName("org_name") - .additionalHeaders(additionalHeaders) - .additionalBodyProperties(additionalBodyProperties) - .additionalQueryParams(additionalQueryParams) + .putAdditionalHeader("Secret-Header", "42") + .putAdditionalQueryParam("secret_query_param", "42") + .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) .build() - - val apiResponse = - Project.builder() - .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .name("name") - .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .settings(ProjectSettings.builder().comparisonKey("comparison_key").build()) - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - - stubFor( - post(anyUrl()) - .withHeader("x-test-header", equalTo("abc1234")) - .withQueryParam("test_query_param", equalTo("def567")) - .withRequestBody(matchingJsonPath("$.testBodyProperty", equalTo("ghi890"))) - .willReturn(ok(JSON_MAPPER.writeValueAsString(apiResponse))) ) - client.projects().create(params) - - verify(postRequestedFor(anyUrl())) + verify( + postRequestedFor(anyUrl()) + .withHeader("Secret-Header", equalTo("42")) + .withQueryParam("secret_query_param", equalTo("42")) + .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) + ) } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/AclServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/AclServiceAsyncTest.kt new file mode 100644 index 00000000..73183c6d --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/AclServiceAsyncTest.kt @@ -0,0 +1,156 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.AclBatchUpdateParams +import com.braintrustdata.api.models.AclCreateParams +import com.braintrustdata.api.models.AclFindAndDeleteParams +import com.braintrustdata.api.models.AclListParams +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.Permission +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class AclServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aclServiceAsync = client.acls() + + val acl = + aclServiceAsync.create( + AclCreateParams.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + + acl.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aclServiceAsync = client.acls() + + val acl = aclServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + acl.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aclServiceAsync = client.acls() + + val page = + aclServiceAsync.list( + AclListParams.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .build() + ) + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aclServiceAsync = client.acls() + + val acl = aclServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + acl.validate() + } + + @Test + suspend fun batchUpdate() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aclServiceAsync = client.acls() + + val aclBatchUpdateResponse = + aclServiceAsync.batchUpdate( + AclBatchUpdateParams.builder() + .addAddAcl( + AclBatchUpdateParams.AddAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .addRemoveAcl( + AclBatchUpdateParams.RemoveAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + ) + + aclBatchUpdateResponse.validate() + } + + @Test + suspend fun findAndDelete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aclServiceAsync = client.acls() + + val acl = + aclServiceAsync.findAndDelete( + AclFindAndDeleteParams.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + + acl.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsyncTest.kt new file mode 100644 index 00000000..bf7dd8e8 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/AiSecretServiceAsyncTest.kt @@ -0,0 +1,157 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.AiSecretCreateParams +import com.braintrustdata.api.models.AiSecretFindAndDeleteParams +import com.braintrustdata.api.models.AiSecretReplaceParams +import com.braintrustdata.api.models.AiSecretUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class AiSecretServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aiSecretServiceAsync = client.aiSecrets() + + val aISecret = + aiSecretServiceAsync.create( + AiSecretCreateParams.builder() + .name("name") + .metadata( + AiSecretCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .orgName("org_name") + .secret("secret") + .type("type") + .build() + ) + + aISecret.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aiSecretServiceAsync = client.aiSecrets() + + val aISecret = aiSecretServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + aISecret.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aiSecretServiceAsync = client.aiSecrets() + + val aISecret = + aiSecretServiceAsync.update( + AiSecretUpdateParams.builder() + .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .metadata( + AiSecretUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .secret("secret") + .type("type") + .build() + ) + + aISecret.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aiSecretServiceAsync = client.aiSecrets() + + val page = aiSecretServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aiSecretServiceAsync = client.aiSecrets() + + val aISecret = aiSecretServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + aISecret.validate() + } + + @Test + suspend fun findAndDelete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aiSecretServiceAsync = client.aiSecrets() + + val aISecret = + aiSecretServiceAsync.findAndDelete( + AiSecretFindAndDeleteParams.builder().name("name").orgName("org_name").build() + ) + + aISecret.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val aiSecretServiceAsync = client.aiSecrets() + + val aISecret = + aiSecretServiceAsync.replace( + AiSecretReplaceParams.builder() + .name("name") + .metadata( + AiSecretReplaceParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .orgName("org_name") + .secret("secret") + .type("type") + .build() + ) + + aISecret.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsyncTest.kt new file mode 100644 index 00000000..38e5857b --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ApiKeyServiceAsyncTest.kt @@ -0,0 +1,72 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.ApiKeyCreateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ApiKeyServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val apiKeyServiceAsync = client.apiKeys() + + val createApiKeyOutput = + apiKeyServiceAsync.create( + ApiKeyCreateParams.builder().name("name").orgName("org_name").build() + ) + + createApiKeyOutput.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val apiKeyServiceAsync = client.apiKeys() + + val apiKey = apiKeyServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + apiKey.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val apiKeyServiceAsync = client.apiKeys() + + val page = apiKeyServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val apiKeyServiceAsync = client.apiKeys() + + val apiKey = apiKeyServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + apiKey.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsyncTest.kt new file mode 100644 index 00000000..476199fd --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/DatasetServiceAsyncTest.kt @@ -0,0 +1,262 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.DatasetCreateParams +import com.braintrustdata.api.models.DatasetFeedbackParams +import com.braintrustdata.api.models.DatasetFetchParams +import com.braintrustdata.api.models.DatasetFetchPostParams +import com.braintrustdata.api.models.DatasetInsertParams +import com.braintrustdata.api.models.DatasetSummarizeParams +import com.braintrustdata.api.models.DatasetUpdateParams +import com.braintrustdata.api.models.FeedbackDatasetItem +import com.braintrustdata.api.models.InsertDatasetEvent +import com.braintrustdata.api.models.ObjectReference +import java.time.OffsetDateTime +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class DatasetServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val dataset = + datasetServiceAsync.create( + DatasetCreateParams.builder() + .name("x") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .metadata( + DatasetCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + + dataset.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val dataset = datasetServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + dataset.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val dataset = + datasetServiceAsync.update( + DatasetUpdateParams.builder() + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .metadata( + DatasetUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .build() + ) + + dataset.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val page = datasetServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val dataset = datasetServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + dataset.validate() + } + + @Test + suspend fun feedback() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val feedbackResponseSchema = + datasetServiceAsync.feedback( + DatasetFeedbackParams.builder() + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addFeedback( + FeedbackDatasetItem.builder() + .id("id") + .comment("comment") + .metadata( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .source(FeedbackDatasetItem.Source.APP) + .addTag("string") + .build() + ) + .build() + ) + + feedbackResponseSchema.validate() + } + + @Test + suspend fun fetch() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val fetchDatasetEventsResponse = + datasetServiceAsync.fetch( + DatasetFetchParams.builder() + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") + .build() + ) + + fetchDatasetEventsResponse.validate() + } + + @Test + suspend fun fetchPost() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val fetchDatasetEventsResponse = + datasetServiceAsync.fetchPost( + DatasetFetchPostParams.builder() + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .cursor("cursor") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") + .build() + ) + + fetchDatasetEventsResponse.validate() + } + + @Test + suspend fun insert() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val insertEventsResponse = + datasetServiceAsync.insert( + DatasetInsertParams.builder() + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addEvent( + InsertDatasetEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertDatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .rootSpanId("root_span_id") + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + ) + .build() + ) + + insertEventsResponse.validate() + } + + @Test + suspend fun summarize() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val datasetServiceAsync = client.datasets() + + val summarizeDatasetResponse = + datasetServiceAsync.summarize( + DatasetSummarizeParams.builder() + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .summarizeData(true) + .build() + ) + + summarizeDatasetResponse.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsyncTest.kt new file mode 100644 index 00000000..4b3f3bf2 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/EnvVarServiceAsyncTest.kt @@ -0,0 +1,133 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.EnvVarCreateParams +import com.braintrustdata.api.models.EnvVarListParams +import com.braintrustdata.api.models.EnvVarObjectType +import com.braintrustdata.api.models.EnvVarReplaceParams +import com.braintrustdata.api.models.EnvVarUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class EnvVarServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val envVarServiceAsync = client.envVars() + + val envVar = + envVarServiceAsync.create( + EnvVarCreateParams.builder() + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(EnvVarCreateParams.ObjectType.ORGANIZATION) + .value("value") + .build() + ) + + envVar.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val envVarServiceAsync = client.envVars() + + val envVar = envVarServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + envVar.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val envVarServiceAsync = client.envVars() + + val envVar = + envVarServiceAsync.update( + EnvVarUpdateParams.builder() + .envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .value("value") + .build() + ) + + envVar.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val envVarServiceAsync = client.envVars() + + val envVars = + envVarServiceAsync.list( + EnvVarListParams.builder() + .envVarName("env_var_name") + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(EnvVarObjectType.ORGANIZATION) + .build() + ) + + envVars.validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val envVarServiceAsync = client.envVars() + + val envVar = envVarServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + envVar.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val envVarServiceAsync = client.envVars() + + val envVar = + envVarServiceAsync.replace( + EnvVarReplaceParams.builder() + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(EnvVarReplaceParams.ObjectType.ORGANIZATION) + .value("value") + .build() + ) + + envVar.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/EvalServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/EvalServiceAsyncTest.kt new file mode 100644 index 00000000..e11706f0 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/EvalServiceAsyncTest.kt @@ -0,0 +1,109 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.EvalCreateParams +import com.braintrustdata.api.models.RepoInfo +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class EvalServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val evalServiceAsync = client.evals() + + val summarizeExperimentResponse = + evalServiceAsync.create( + EvalCreateParams.builder() + .data( + EvalCreateParams.Data.DatasetId.builder() + .datasetId("dataset_id") + ._internalBtql( + EvalCreateParams.Data.DatasetId._InternalBtql + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .projectId("project_id") + .addScore( + EvalCreateParams.Score.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() + ) + .task( + EvalCreateParams.Task.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() + ) + .baseExperimentId("base_experiment_id") + .baseExperimentName("base_experiment_name") + .experimentName("experiment_name") + .gitMetadataSettings( + EvalCreateParams.GitMetadataSettings.builder() + .collect(EvalCreateParams.GitMetadataSettings.Collect.ALL) + .addField(EvalCreateParams.GitMetadataSettings.Field.COMMIT) + .build() + ) + .isPublic(true) + .maxConcurrency(0.0) + .metadata( + EvalCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .parent( + EvalCreateParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType( + EvalCreateParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS + ) + .propagatedEvent( + EvalCreateParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + EvalCreateParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) + .stream(true) + .timeout(0.0) + .trialCount(0.0) + .build() + ) + + summarizeExperimentResponse.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsyncTest.kt new file mode 100644 index 00000000..48ec51be --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ExperimentServiceAsyncTest.kt @@ -0,0 +1,338 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.ExperimentCreateParams +import com.braintrustdata.api.models.ExperimentFeedbackParams +import com.braintrustdata.api.models.ExperimentFetchParams +import com.braintrustdata.api.models.ExperimentFetchPostParams +import com.braintrustdata.api.models.ExperimentInsertParams +import com.braintrustdata.api.models.ExperimentSummarizeParams +import com.braintrustdata.api.models.ExperimentUpdateParams +import com.braintrustdata.api.models.FeedbackExperimentItem +import com.braintrustdata.api.models.InsertExperimentEvent +import com.braintrustdata.api.models.ObjectReference +import com.braintrustdata.api.models.RepoInfo +import com.braintrustdata.api.models.SpanAttributes +import com.braintrustdata.api.models.SpanType +import java.time.OffsetDateTime +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ExperimentServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val experiment = + experimentServiceAsync.create( + ExperimentCreateParams.builder() + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetVersion("dataset_version") + .description("description") + .ensureNew(true) + .metadata( + ExperimentCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("x") + .public_(true) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) + .build() + ) + + experiment.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val experiment = experimentServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + experiment.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val experiment = + experimentServiceAsync.update( + ExperimentUpdateParams.builder() + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .baseExpId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .datasetVersion("dataset_version") + .description("description") + .metadata( + ExperimentUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .public_(true) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) + .build() + ) + + experiment.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val page = experimentServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val experiment = experimentServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + experiment.validate() + } + + @Test + suspend fun feedback() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val feedbackResponseSchema = + experimentServiceAsync.feedback( + ExperimentFeedbackParams.builder() + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addFeedback( + FeedbackExperimentItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackExperimentItem.Source.APP) + .addTag("string") + .build() + ) + .build() + ) + + feedbackResponseSchema.validate() + } + + @Test + suspend fun fetch() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val fetchExperimentEventsResponse = + experimentServiceAsync.fetch( + ExperimentFetchParams.builder() + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") + .build() + ) + + fetchExperimentEventsResponse.validate() + } + + @Test + suspend fun fetchPost() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val fetchExperimentEventsResponse = + experimentServiceAsync.fetchPost( + ExperimentFetchPostParams.builder() + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .cursor("cursor") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") + .build() + ) + + fetchExperimentEventsResponse.validate() + } + + @Test + suspend fun insert() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val insertEventsResponse = + experimentServiceAsync.insert( + ExperimentInsertParams.builder() + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addEvent( + InsertExperimentEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata( + InsertExperimentEvent.Metadata.builder().model("model").build() + ) + .metrics( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + ) + .build() + ) + + insertEventsResponse.validate() + } + + @Test + suspend fun summarize() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val experimentServiceAsync = client.experiments() + + val summarizeExperimentResponse = + experimentServiceAsync.summarize( + ExperimentSummarizeParams.builder() + .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .summarizeScores(true) + .build() + ) + + summarizeExperimentResponse.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsyncTest.kt new file mode 100644 index 00000000..65b15062 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/FunctionServiceAsyncTest.kt @@ -0,0 +1,476 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.FunctionCreateParams +import com.braintrustdata.api.models.FunctionInvokeParams +import com.braintrustdata.api.models.FunctionReplaceParams +import com.braintrustdata.api.models.FunctionUpdateParams +import com.braintrustdata.api.models.PromptData +import com.braintrustdata.api.models.PromptOptions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class FunctionServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val functionServiceAsync = client.functions() + + val function = + functionServiceAsync.create( + FunctionCreateParams.builder() + .functionData( + FunctionCreateParams.FunctionData.Prompt.builder() + .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) + .build() + ) + .name("x") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("x") + .description("description") + .functionSchema( + FunctionCreateParams.FunctionSchema.builder() + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) + .build() + ) + .functionType(FunctionCreateParams.FunctionType.LLM) + .origin( + FunctionCreateParams.Origin.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .internal_(true) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + + function.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val functionServiceAsync = client.functions() + + val function = functionServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + function.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val functionServiceAsync = client.functions() + + val function = + functionServiceAsync.update( + FunctionUpdateParams.builder() + .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .functionData( + FunctionUpdateParams.FunctionData.Prompt.builder() + .type(FunctionUpdateParams.FunctionData.Prompt.Type.PROMPT) + .build() + ) + .name("name") + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + + function.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val functionServiceAsync = client.functions() + + val page = functionServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val functionServiceAsync = client.functions() + + val function = functionServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + function.validate() + } + + @Test + suspend fun invoke() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val functionServiceAsync = client.functions() + + val response = + functionServiceAsync.invoke( + FunctionInvokeParams.builder() + .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .addMessage( + FunctionInvokeParams.Message.System.builder() + .role(FunctionInvokeParams.Message.System.Role.SYSTEM) + .content("content") + .name("name") + .build() + ) + .metadata( + FunctionInvokeParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .mode(FunctionInvokeParams.Mode.AUTO) + .parent( + FunctionInvokeParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType( + FunctionInvokeParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS + ) + .propagatedEvent( + FunctionInvokeParams.Parent.SpanParentStruct.PropagatedEvent + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + FunctionInvokeParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() + ) + .stream(true) + .version("version") + .build() + ) + + response?.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val functionServiceAsync = client.functions() + + val function = + functionServiceAsync.replace( + FunctionReplaceParams.builder() + .functionData( + FunctionReplaceParams.FunctionData.Prompt.builder() + .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) + .build() + ) + .name("x") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("x") + .description("description") + .functionSchema( + FunctionReplaceParams.FunctionSchema.builder() + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) + .build() + ) + .functionType(FunctionReplaceParams.FunctionType.LLM) + .origin( + FunctionReplaceParams.Origin.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .internal_(true) + .build() + ) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + + function.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/GroupServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/GroupServiceAsyncTest.kt new file mode 100644 index 00000000..64ae3de5 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/GroupServiceAsyncTest.kt @@ -0,0 +1,128 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.GroupCreateParams +import com.braintrustdata.api.models.GroupReplaceParams +import com.braintrustdata.api.models.GroupUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class GroupServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val groupServiceAsync = client.groups() + + val group = + groupServiceAsync.create( + GroupCreateParams.builder() + .name("x") + .description("description") + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgName("org_name") + .build() + ) + + group.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val groupServiceAsync = client.groups() + + val group = groupServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + group.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val groupServiceAsync = client.groups() + + val group = + groupServiceAsync.update( + GroupUpdateParams.builder() + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addAddMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addAddMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .name("x") + .addRemoveMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addRemoveMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + + group.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val groupServiceAsync = client.groups() + + val page = groupServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val groupServiceAsync = client.groups() + + val group = groupServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + group.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val groupServiceAsync = client.groups() + + val group = + groupServiceAsync.replace( + GroupReplaceParams.builder() + .name("x") + .description("description") + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgName("org_name") + .build() + ) + + group.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsyncTest.kt new file mode 100644 index 00000000..20970ccb --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/OrganizationServiceAsyncTest.kt @@ -0,0 +1,79 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.OrganizationUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class OrganizationServiceAsyncTest { + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val organizationServiceAsync = client.organizations() + + val organization = organizationServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + organization.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val organizationServiceAsync = client.organizations() + + val organization = + organizationServiceAsync.update( + OrganizationUpdateParams.builder() + .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .apiUrl("api_url") + .isUniversalApi(true) + .name("name") + .proxyUrl("proxy_url") + .realtimeUrl("realtime_url") + .build() + ) + + organization.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val organizationServiceAsync = client.organizations() + + val page = organizationServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val organizationServiceAsync = client.organizations() + + val organization = organizationServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + organization.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsyncTest.kt new file mode 100644 index 00000000..be7e2fdb --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectScoreServiceAsyncTest.kt @@ -0,0 +1,193 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.OnlineScoreConfig +import com.braintrustdata.api.models.ProjectScoreCategory +import com.braintrustdata.api.models.ProjectScoreConfig +import com.braintrustdata.api.models.ProjectScoreCreateParams +import com.braintrustdata.api.models.ProjectScoreReplaceParams +import com.braintrustdata.api.models.ProjectScoreType +import com.braintrustdata.api.models.ProjectScoreUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ProjectScoreServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectScoreServiceAsync = client.projectScores() + + val projectScore = + projectScoreServiceAsync.create( + ProjectScoreCreateParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .scoreType(ProjectScoreType.SLIDER) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) + ) + .config( + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + ) + .description("description") + .build() + ) + + projectScore.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectScoreServiceAsync = client.projectScores() + + val projectScore = projectScoreServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + projectScore.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectScoreServiceAsync = client.projectScores() + + val projectScore = + projectScoreServiceAsync.update( + ProjectScoreUpdateParams.builder() + .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) + ) + .config( + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + ) + .description("description") + .name("name") + .scoreType(ProjectScoreType.SLIDER) + .build() + ) + + projectScore.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectScoreServiceAsync = client.projectScores() + + val page = projectScoreServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectScoreServiceAsync = client.projectScores() + + val projectScore = projectScoreServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + projectScore.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectScoreServiceAsync = client.projectScores() + + val projectScore = + projectScoreServiceAsync.replace( + ProjectScoreReplaceParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .scoreType(ProjectScoreType.SLIDER) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) + ) + .config( + ProjectScoreConfig.builder() + .destination("destination") + .multiSelect(true) + .online( + OnlineScoreConfig.builder() + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() + ) + .applyToRootSpan(true) + .addApplyToSpanName("string") + .build() + ) + .build() + ) + .description("description") + .build() + ) + + projectScore.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsyncTest.kt new file mode 100644 index 00000000..f4f6e48d --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectServiceAsyncTest.kt @@ -0,0 +1,108 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.ProjectCreateParams +import com.braintrustdata.api.models.ProjectSettings +import com.braintrustdata.api.models.ProjectUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ProjectServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectServiceAsync = client.projects() + + val project = + projectServiceAsync.create( + ProjectCreateParams.builder().name("x").orgName("org_name").build() + ) + + project.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectServiceAsync = client.projects() + + val project = projectServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + project.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectServiceAsync = client.projects() + + val project = + projectServiceAsync.update( + ProjectUpdateParams.builder() + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) + .build() + ) + + project.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectServiceAsync = client.projects() + + val page = projectServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectServiceAsync = client.projects() + + val project = projectServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + project.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsyncTest.kt new file mode 100644 index 00000000..e3a3d681 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ProjectTagServiceAsyncTest.kt @@ -0,0 +1,123 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.ProjectTagCreateParams +import com.braintrustdata.api.models.ProjectTagReplaceParams +import com.braintrustdata.api.models.ProjectTagUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ProjectTagServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectTagServiceAsync = client.projectTags() + + val projectTag = + projectTagServiceAsync.create( + ProjectTagCreateParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .description("description") + .build() + ) + + projectTag.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectTagServiceAsync = client.projectTags() + + val projectTag = projectTagServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + projectTag.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectTagServiceAsync = client.projectTags() + + val projectTag = + projectTagServiceAsync.update( + ProjectTagUpdateParams.builder() + .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .description("description") + .name("name") + .build() + ) + + projectTag.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectTagServiceAsync = client.projectTags() + + val page = projectTagServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectTagServiceAsync = client.projectTags() + + val projectTag = projectTagServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + projectTag.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val projectTagServiceAsync = client.projectTags() + + val projectTag = + projectTagServiceAsync.replace( + ProjectTagReplaceParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .color("color") + .description("description") + .build() + ) + + projectTag.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/PromptServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/PromptServiceAsyncTest.kt new file mode 100644 index 00000000..c0a5f0b4 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/PromptServiceAsyncTest.kt @@ -0,0 +1,377 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.PromptCreateParams +import com.braintrustdata.api.models.PromptData +import com.braintrustdata.api.models.PromptOptions +import com.braintrustdata.api.models.PromptReplaceParams +import com.braintrustdata.api.models.PromptUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class PromptServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val promptServiceAsync = client.prompts() + + val prompt = + promptServiceAsync.create( + PromptCreateParams.builder() + .name("x") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("x") + .description("description") + .functionType(PromptCreateParams.FunctionType.LLM) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + + prompt.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val promptServiceAsync = client.prompts() + + val prompt = promptServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + prompt.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val promptServiceAsync = client.prompts() + + val prompt = + promptServiceAsync.update( + PromptUpdateParams.builder() + .promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .name("name") + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .slug("slug") + .addTag("string") + .build() + ) + + prompt.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val promptServiceAsync = client.prompts() + + val page = promptServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val promptServiceAsync = client.prompts() + + val prompt = promptServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + prompt.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val promptServiceAsync = client.prompts() + + val prompt = + promptServiceAsync.replace( + PromptReplaceParams.builder() + .name("x") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .slug("x") + .description("description") + .functionType(PromptReplaceParams.FunctionType.LLM) + .promptData( + PromptData.builder() + .options( + PromptOptions.builder() + .model("model") + .params( + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() + ) + .position("position") + .build() + ) + .origin( + PromptData.Origin.builder() + .projectId("project_id") + .promptId("prompt_id") + .promptVersion("prompt_version") + .build() + ) + .parser( + PromptData.Parser.builder() + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .type(PromptData.Parser.Type.LLM_CLASSIFIER) + .useCot(true) + .build() + ) + .prompt( + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() + ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() + ) + .build() + ) + .addTag("string") + .build() + ) + + prompt.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/RoleServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/RoleServiceAsyncTest.kt new file mode 100644 index 00000000..12fde3d5 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/RoleServiceAsyncTest.kt @@ -0,0 +1,150 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.Permission +import com.braintrustdata.api.models.RoleCreateParams +import com.braintrustdata.api.models.RoleReplaceParams +import com.braintrustdata.api.models.RoleUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class RoleServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val roleServiceAsync = client.roles() + + val role = + roleServiceAsync.create( + RoleCreateParams.builder() + .name("x") + .description("description") + .addMemberPermission( + RoleCreateParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgName("org_name") + .build() + ) + + role.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val roleServiceAsync = client.roles() + + val role = roleServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + role.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val roleServiceAsync = client.roles() + + val role = + roleServiceAsync.update( + RoleUpdateParams.builder() + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addAddMemberPermission( + RoleUpdateParams.AddMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addAddMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .name("x") + .addRemoveMemberPermission( + RoleUpdateParams.RemoveMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addRemoveMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + + role.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val roleServiceAsync = client.roles() + + val page = roleServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val roleServiceAsync = client.roles() + + val role = roleServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + role.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val roleServiceAsync = client.roles() + + val role = + roleServiceAsync.replace( + RoleReplaceParams.builder() + .name("x") + .description("description") + .addMemberPermission( + RoleReplaceParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() + ) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .orgName("org_name") + .build() + ) + + role.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsyncTest.kt new file mode 100644 index 00000000..07567626 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/SpanIframeServiceAsyncTest.kt @@ -0,0 +1,126 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.SpanIframeCreateParams +import com.braintrustdata.api.models.SpanIframeReplaceParams +import com.braintrustdata.api.models.SpanIframeUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class SpanIframeServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeServiceAsync = client.spanIframes() + + val spanIFrame = + spanIframeServiceAsync.create( + SpanIframeCreateParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + ) + + spanIFrame.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeServiceAsync = client.spanIframes() + + val spanIFrame = spanIframeServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + spanIFrame.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeServiceAsync = client.spanIframes() + + val spanIFrame = + spanIframeServiceAsync.update( + SpanIframeUpdateParams.builder() + .spanIframeId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .name("name") + .postMessage(true) + .url("url") + .build() + ) + + spanIFrame.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeServiceAsync = client.spanIframes() + + val page = spanIframeServiceAsync.list() + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeServiceAsync = client.spanIframes() + + val spanIFrame = spanIframeServiceAsync.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + spanIFrame.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeServiceAsync = client.spanIframes() + + val spanIFrame = + spanIframeServiceAsync.replace( + SpanIframeReplaceParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + ) + + spanIFrame.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsyncTest.kt new file mode 100644 index 00000000..b6b56d8a --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/TopLevelServiceAsyncTest.kt @@ -0,0 +1,24 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class TopLevelServiceAsyncTest { + + @Test + suspend fun helloWorld() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val topLevelServiceAsync = client.topLevel() + + topLevelServiceAsync.helloWorld() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/UserServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/UserServiceAsyncTest.kt new file mode 100644 index 00000000..4e8a876d --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/UserServiceAsyncTest.kt @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class UserServiceAsyncTest { + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val userServiceAsync = client.users() + + val user = userServiceAsync.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + user.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val userServiceAsync = client.users() + + val page = userServiceAsync.list() + + page.response().validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ViewServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ViewServiceAsyncTest.kt new file mode 100644 index 00000000..d2f6229f --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/ViewServiceAsyncTest.kt @@ -0,0 +1,248 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.ViewCreateParams +import com.braintrustdata.api.models.ViewData +import com.braintrustdata.api.models.ViewDataSearch +import com.braintrustdata.api.models.ViewDeleteParams +import com.braintrustdata.api.models.ViewListParams +import com.braintrustdata.api.models.ViewOptions +import com.braintrustdata.api.models.ViewReplaceParams +import com.braintrustdata.api.models.ViewRetrieveParams +import com.braintrustdata.api.models.ViewUpdateParams +import java.time.OffsetDateTime +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ViewServiceAsyncTest { + + @Test + suspend fun create() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val viewServiceAsync = client.views() + + val view = + viewServiceAsync.create( + ViewCreateParams.builder() + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .viewType(ViewCreateParams.ViewType.PROJECTS) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .options( + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .viewData( + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + ) + .build() + ) + + view.validate() + } + + @Test + suspend fun retrieve() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val viewServiceAsync = client.views() + + val view = + viewServiceAsync.retrieve( + ViewRetrieveParams.builder() + .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .build() + ) + + view.validate() + } + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val viewServiceAsync = client.views() + + val view = + viewServiceAsync.update( + ViewUpdateParams.builder() + .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .name("name") + .options( + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .viewData( + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + ) + .viewType(ViewUpdateParams.ViewType.PROJECTS) + .build() + ) + + view.validate() + } + + @Test + suspend fun list() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val viewServiceAsync = client.views() + + val page = + viewServiceAsync.list( + ViewListParams.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .build() + ) + + page.response().validate() + } + + @Test + suspend fun delete() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val viewServiceAsync = client.views() + + val view = + viewServiceAsync.delete( + ViewDeleteParams.builder() + .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .build() + ) + + view.validate() + } + + @Test + suspend fun replace() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val viewServiceAsync = client.views() + + val view = + viewServiceAsync.replace( + ViewReplaceParams.builder() + .name("name") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .viewType(ViewReplaceParams.ViewType.PROJECTS) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .options( + ViewOptions.builder() + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .viewData( + ViewData.builder() + .search( + ViewDataSearch.builder() + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) + .build() + ) + .build() + ) + .build() + ) + + view.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsyncTest.kt new file mode 100644 index 00000000..30a75854 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/organizations/MemberServiceAsyncTest.kt @@ -0,0 +1,50 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async.organizations + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.models.OrganizationMemberUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class MemberServiceAsyncTest { + + @Test + suspend fun update() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val memberServiceAsync = client.organizations().members() + + val patchOrganizationMembersOutput = + memberServiceAsync.update( + OrganizationMemberUpdateParams.builder() + .inviteUsers( + OrganizationMemberUpdateParams.InviteUsers.builder() + .addEmail("string") + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addGroupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .groupName("group_name") + .addGroupName("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .sendInviteEmails(true) + .build() + ) + .orgId("org_id") + .orgName("org_name") + .removeUsers( + OrganizationMemberUpdateParams.RemoveUsers.builder() + .addEmail("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + ) + + patchOrganizationMembersOutput.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsyncTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsyncTest.kt new file mode 100644 index 00000000..d46bcd99 --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/async/projects/LogServiceAsyncTest.kt @@ -0,0 +1,184 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.async.projects + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClientAsync +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.FeedbackProjectLogsItem +import com.braintrustdata.api.models.InsertProjectLogsEvent +import com.braintrustdata.api.models.ObjectReference +import com.braintrustdata.api.models.ProjectLogFeedbackParams +import com.braintrustdata.api.models.ProjectLogFetchParams +import com.braintrustdata.api.models.ProjectLogFetchPostParams +import com.braintrustdata.api.models.ProjectLogInsertParams +import com.braintrustdata.api.models.SpanAttributes +import com.braintrustdata.api.models.SpanType +import java.time.OffsetDateTime +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class LogServiceAsyncTest { + + @Test + suspend fun feedback() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val logServiceAsync = client.projects().logs() + + val feedbackResponseSchema = + logServiceAsync.feedback( + ProjectLogFeedbackParams.builder() + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addFeedback( + FeedbackProjectLogsItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackProjectLogsItem.Source.APP) + .addTag("string") + .build() + ) + .build() + ) + + feedbackResponseSchema.validate() + } + + @Test + suspend fun fetch() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val logServiceAsync = client.projects().logs() + + val fetchProjectLogsEventsResponse = + logServiceAsync.fetch( + ProjectLogFetchParams.builder() + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") + .build() + ) + + fetchProjectLogsEventsResponse.validate() + } + + @Test + suspend fun fetchPost() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val logServiceAsync = client.projects().logs() + + val fetchProjectLogsEventsResponse = + logServiceAsync.fetchPost( + ProjectLogFetchPostParams.builder() + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .cursor("cursor") + .limit(0L) + .maxRootSpanId("max_root_span_id") + .maxXactId("max_xact_id") + .version("version") + .build() + ) + + fetchProjectLogsEventsResponse.validate() + } + + @Test + suspend fun insert() { + val client = + BraintrustOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val logServiceAsync = client.projects().logs() + + val insertEventsResponse = + logServiceAsync.insert( + ProjectLogInsertParams.builder() + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addEvent( + InsertProjectLogsEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata( + InsertProjectLogsEvent.Metadata.builder().model("model").build() + ) + .metrics( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() + .id("id") + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() + ) + .build() + ) + + insertEventsResponse.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AclServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AclServiceTest.kt index 20c3d3f6..7838f8f7 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AclServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AclServiceTest.kt @@ -4,157 +4,153 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* +import com.braintrustdata.api.models.AclBatchUpdateParams +import com.braintrustdata.api.models.AclCreateParams +import com.braintrustdata.api.models.AclFindAndDeleteParams import com.braintrustdata.api.models.AclListParams +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.Permission import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class AclServiceTest { +internal class AclServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aclService = client.acls() + val acl = aclService.create( AclCreateParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclCreateParams.Permission.CREATE) - .restrictObjectType(AclCreateParams.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) - println(acl) + acl.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aclService = client.acls() - val acl = - aclService.retrieve( - AclRetrieveParams.builder().aclId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - ) - println(acl) + + val acl = aclService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + acl.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aclService = client.acls() - val response = + + val page = aclService.list( AclListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() ) - println(response) - response.objects().forEach { it.validate() } + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aclService = client.acls() - val acl = - aclService.delete( - AclDeleteParams.builder().aclId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - ) - println(acl) + + val acl = aclService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + acl.validate() } @Test - fun callBatchUpdate() { + fun batchUpdate() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aclService = client.acls() + val aclBatchUpdateResponse = aclService.batchUpdate( AclBatchUpdateParams.builder() - .addAcls( - listOf( - AclBatchUpdateParams.AddAcl.builder() - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.AddAcl.ObjectType.ORGANIZATION) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.AddAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.AddAcl.RestrictObjectType.ORGANIZATION - ) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) + .addAddAcl( + AclBatchUpdateParams.AddAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) - .removeAcls( - listOf( - AclBatchUpdateParams.RemoveAcl.builder() - .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclBatchUpdateParams.RemoveAcl.ObjectType.ORGANIZATION) - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclBatchUpdateParams.RemoveAcl.Permission.CREATE) - .restrictObjectType( - AclBatchUpdateParams.RemoveAcl.RestrictObjectType.ORGANIZATION - ) - .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) + .addRemoveAcl( + AclBatchUpdateParams.RemoveAcl.builder() + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(AclObjectType.ORGANIZATION) + .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() ) .build() ) - println(aclBatchUpdateResponse) + aclBatchUpdateResponse.validate() } @Test - fun callFindAndDelete() { + fun findAndDelete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aclService = client.acls() + val acl = aclService.findAndDelete( AclFindAndDeleteParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(AclFindAndDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .permission(AclFindAndDeleteParams.Permission.CREATE) - .restrictObjectType(AclFindAndDeleteParams.RestrictObjectType.ORGANIZATION) + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) - println(acl) + acl.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceTest.kt index 2eb15e81..911cdcdb 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/AiSecretServiceTest.kt @@ -4,142 +4,154 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.AiSecretListParams +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.AiSecretCreateParams +import com.braintrustdata.api.models.AiSecretFindAndDeleteParams +import com.braintrustdata.api.models.AiSecretReplaceParams +import com.braintrustdata.api.models.AiSecretUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class AiSecretServiceTest { +internal class AiSecretServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aiSecretService = client.aiSecrets() + val aISecret = aiSecretService.create( AiSecretCreateParams.builder() .name("name") - .metadata(AiSecretCreateParams.Metadata.builder().build()) + .metadata( + AiSecretCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .orgName("org_name") .secret("secret") .type("type") .build() ) - println(aISecret) + aISecret.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aiSecretService = client.aiSecrets() - val aISecret = - aiSecretService.retrieve( - AiSecretRetrieveParams.builder() - .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(aISecret) + + val aISecret = aiSecretService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + aISecret.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aiSecretService = client.aiSecrets() + val aISecret = aiSecretService.update( AiSecretUpdateParams.builder() .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .metadata(AiSecretUpdateParams.Metadata.builder().build()) + .metadata( + AiSecretUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .secret("secret") .type("type") .build() ) - println(aISecret) + aISecret.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aiSecretService = client.aiSecrets() - val response = aiSecretService.list(AiSecretListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = aiSecretService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aiSecretService = client.aiSecrets() - val aISecret = - aiSecretService.delete( - AiSecretDeleteParams.builder() - .aiSecretId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(aISecret) + + val aISecret = aiSecretService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + aISecret.validate() } @Test - fun callFindAndDelete() { + fun findAndDelete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aiSecretService = client.aiSecrets() + val aISecret = aiSecretService.findAndDelete( AiSecretFindAndDeleteParams.builder().name("name").orgName("org_name").build() ) - println(aISecret) + aISecret.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val aiSecretService = client.aiSecrets() + val aISecret = aiSecretService.replace( AiSecretReplaceParams.builder() .name("name") - .metadata(AiSecretReplaceParams.Metadata.builder().build()) + .metadata( + AiSecretReplaceParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .orgName("org_name") .secret("secret") .type("type") .build() ) - println(aISecret) + aISecret.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceTest.kt index bef46629..471eaa44 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ApiKeyServiceTest.kt @@ -4,76 +4,69 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.ApiKeyListParams +import com.braintrustdata.api.models.ApiKeyCreateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class ApiKeyServiceTest { +internal class ApiKeyServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val apiKeyService = client.apiKeys() + val createApiKeyOutput = apiKeyService.create( ApiKeyCreateParams.builder().name("name").orgName("org_name").build() ) - println(createApiKeyOutput) + createApiKeyOutput.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val apiKeyService = client.apiKeys() - val apiKey = - apiKeyService.retrieve( - ApiKeyRetrieveParams.builder() - .apiKeyId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(apiKey) + + val apiKey = apiKeyService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + apiKey.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val apiKeyService = client.apiKeys() - val response = apiKeyService.list(ApiKeyListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = apiKeyService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val apiKeyService = client.apiKeys() - val apiKey = - apiKeyService.delete( - ApiKeyDeleteParams.builder() - .apiKeyId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(apiKey) + + val apiKey = apiKeyService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + apiKey.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceTest.kt index 8a9ef54d..b2f77a0b 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/DatasetServiceTest.kt @@ -4,231 +4,251 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.DatasetListParams +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.DatasetCreateParams +import com.braintrustdata.api.models.DatasetFeedbackParams +import com.braintrustdata.api.models.DatasetFetchParams +import com.braintrustdata.api.models.DatasetFetchPostParams +import com.braintrustdata.api.models.DatasetInsertParams +import com.braintrustdata.api.models.DatasetSummarizeParams +import com.braintrustdata.api.models.DatasetUpdateParams +import com.braintrustdata.api.models.FeedbackDatasetItem +import com.braintrustdata.api.models.InsertDatasetEvent +import com.braintrustdata.api.models.ObjectReference import java.time.OffsetDateTime import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class DatasetServiceTest { +internal class DatasetServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() + val dataset = datasetService.create( DatasetCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") + .metadata( + DatasetCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() ) - println(dataset) + dataset.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() - val dataset = - datasetService.retrieve( - DatasetRetrieveParams.builder() - .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(dataset) + + val dataset = datasetService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + dataset.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() + val dataset = datasetService.update( DatasetUpdateParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .metadata(DatasetUpdateParams.Metadata.builder().build()) + .metadata( + DatasetUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .build() ) - println(dataset) + dataset.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() - val response = datasetService.list(DatasetListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = datasetService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() - val dataset = - datasetService.delete( - DatasetDeleteParams.builder() - .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(dataset) + + val dataset = datasetService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + dataset.validate() } @Test - fun callFeedback() { + fun feedback() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() + val feedbackResponseSchema = datasetService.feedback( DatasetFeedbackParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackDatasetItem.builder() - .id("id") - .comment("comment") - .metadata(FeedbackDatasetItem.Metadata.builder().build()) - .source(FeedbackDatasetItem.Source.APP) - .build() - ) + .addFeedback( + FeedbackDatasetItem.builder() + .id("id") + .comment("comment") + .metadata( + FeedbackDatasetItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .source(FeedbackDatasetItem.Source.APP) + .addTag("string") + .build() ) .build() ) - println(feedbackResponseSchema) + feedbackResponseSchema.validate() } @Test - fun callFetch() { + fun fetch() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() + val fetchDatasetEventsResponse = datasetService.fetch( DatasetFetchParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() ) - println(fetchDatasetEventsResponse) + fetchDatasetEventsResponse.validate() } @Test - fun callFetchPost() { + fun fetchPost() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() + val fetchDatasetEventsResponse = datasetService.fetchPost( DatasetFetchPostParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() ) - println(fetchDatasetEventsResponse) + fetchDatasetEventsResponse.validate() } @Test - fun callInsert() { + fun insert() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() + val insertEventsResponse = datasetService.insert( DatasetInsertParams.builder() .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - DatasetInsertParams.Event.ofInsertDatasetEventReplace( - InsertDatasetEventReplace.builder() + .addEvent( + InsertDatasetEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata(InsertDatasetEvent.Metadata.builder().model("model").build()) + .origin( + ObjectReference.builder() .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata(InsertDatasetEventReplace.Metadata.builder().build()) - .tags(listOf("string")) + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") .build() ) - ) + .rootSpanId("root_span_id") + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() ) - println(insertEventsResponse) + insertEventsResponse.validate() } @Test - fun callSummarize() { + fun summarize() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val datasetService = client.datasets() + val summarizeDatasetResponse = datasetService.summarize( DatasetSummarizeParams.builder() @@ -236,7 +256,7 @@ class DatasetServiceTest { .summarizeData(true) .build() ) - println(summarizeDatasetResponse) + summarizeDatasetResponse.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceTest.kt index 81350114..04d3edce 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EnvVarServiceTest.kt @@ -4,21 +4,26 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* +import com.braintrustdata.api.models.EnvVarCreateParams +import com.braintrustdata.api.models.EnvVarListParams +import com.braintrustdata.api.models.EnvVarObjectType +import com.braintrustdata.api.models.EnvVarReplaceParams +import com.braintrustdata.api.models.EnvVarUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class EnvVarServiceTest { +internal class EnvVarServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val envVarService = client.envVars() + val envVar = envVarService.create( EnvVarCreateParams.builder() @@ -28,36 +33,33 @@ class EnvVarServiceTest { .value("value") .build() ) - println(envVar) + envVar.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val envVarService = client.envVars() - val envVar = - envVarService.retrieve( - EnvVarRetrieveParams.builder() - .envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(envVar) + + val envVar = envVarService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + envVar.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val envVarService = client.envVars() + val envVar = envVarService.update( EnvVarUpdateParams.builder() @@ -66,57 +68,56 @@ class EnvVarServiceTest { .value("value") .build() ) - println(envVar) + envVar.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val envVarService = client.envVars() - val envVarListResponse = + + val envVars = envVarService.list( EnvVarListParams.builder() .envVarName("env_var_name") - .limit(123L) + .ids("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .limit(0L) .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(EnvVarListParams.ObjectType.ORGANIZATION) + .objectType(EnvVarObjectType.ORGANIZATION) .build() ) - println(envVarListResponse) - envVarListResponse.validate() + + envVars.validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val envVarService = client.envVars() - val envVar = - envVarService.delete( - EnvVarDeleteParams.builder() - .envVarId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(envVar) + + val envVar = envVarService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + envVar.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val envVarService = client.envVars() + val envVar = envVarService.replace( EnvVarReplaceParams.builder() @@ -126,7 +127,7 @@ class EnvVarServiceTest { .value("value") .build() ) - println(envVar) + envVar.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EvalServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EvalServiceTest.kt index c2ee858f..2409d221 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EvalServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/EvalServiceTest.kt @@ -4,56 +4,106 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.EvalCreateParams +import com.braintrustdata.api.models.RepoInfo import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class EvalServiceTest { +internal class EvalServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val evalService = client.evals() + val summarizeExperimentResponse = evalService.create( EvalCreateParams.builder() .data( - EvalCreateParams.Data.ofDatasetId( - EvalCreateParams.Data.DatasetId.builder() - .datasetId("dataset_id") - .build() - ) - ) - .projectId("project_id") - .scores( - listOf( - EvalCreateParams.Score.ofFunctionId( - EvalCreateParams.Score.FunctionId.builder() - .functionId("function_id") - .version("version") + EvalCreateParams.Data.DatasetId.builder() + .datasetId("dataset_id") + ._internalBtql( + EvalCreateParams.Data.DatasetId._InternalBtql + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) - ) + .build() + ) + .projectId("project_id") + .addScore( + EvalCreateParams.Score.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() ) .task( - EvalCreateParams.Task.ofFunctionId( - EvalCreateParams.Task.FunctionId.builder() - .functionId("function_id") - .version("version") - .build() - ) + EvalCreateParams.Task.FunctionId.builder() + .functionId("function_id") + .version("version") + .build() ) + .baseExperimentId("base_experiment_id") + .baseExperimentName("base_experiment_name") .experimentName("experiment_name") - .metadata(EvalCreateParams.Metadata.builder().build()) + .gitMetadataSettings( + EvalCreateParams.GitMetadataSettings.builder() + .collect(EvalCreateParams.GitMetadataSettings.Collect.ALL) + .addField(EvalCreateParams.GitMetadataSettings.Field.COMMIT) + .build() + ) + .isPublic(true) + .maxConcurrency(0.0) + .metadata( + EvalCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .parent( + EvalCreateParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType( + EvalCreateParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS + ) + .propagatedEvent( + EvalCreateParams.Parent.SpanParentStruct.PropagatedEvent.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + EvalCreateParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() + ) + .repoInfo( + RepoInfo.builder() + .authorEmail("author_email") + .authorName("author_name") + .branch("branch") + .commit("commit") + .commitMessage("commit_message") + .commitTime("commit_time") + .dirty(true) + .gitDiff("git_diff") + .tag("tag") + .build() + ) .stream(true) + .timeout(0.0) + .trialCount(0.0) .build() ) - println(summarizeExperimentResponse) + summarizeExperimentResponse.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceTest.kt index 878d2ace..cccec10d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ExperimentServiceTest.kt @@ -4,24 +4,36 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.ExperimentListParams +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.ExperimentCreateParams +import com.braintrustdata.api.models.ExperimentFeedbackParams +import com.braintrustdata.api.models.ExperimentFetchParams +import com.braintrustdata.api.models.ExperimentFetchPostParams +import com.braintrustdata.api.models.ExperimentInsertParams +import com.braintrustdata.api.models.ExperimentSummarizeParams +import com.braintrustdata.api.models.ExperimentUpdateParams +import com.braintrustdata.api.models.FeedbackExperimentItem +import com.braintrustdata.api.models.InsertExperimentEvent +import com.braintrustdata.api.models.ObjectReference +import com.braintrustdata.api.models.RepoInfo +import com.braintrustdata.api.models.SpanAttributes +import com.braintrustdata.api.models.SpanType import java.time.OffsetDateTime import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class ExperimentServiceTest { +internal class ExperimentServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() + val experiment = experimentService.create( ExperimentCreateParams.builder() @@ -31,8 +43,12 @@ class ExperimentServiceTest { .datasetVersion("dataset_version") .description("description") .ensureNew(true) - .metadata(ExperimentCreateParams.Metadata.builder().build()) - .name("name") + .metadata( + ExperimentCreateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("x") .public_(true) .repoInfo( RepoInfo.builder() @@ -49,36 +65,33 @@ class ExperimentServiceTest { ) .build() ) - println(experiment) + experiment.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() - val experiment = - experimentService.retrieve( - ExperimentRetrieveParams.builder() - .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(experiment) + + val experiment = experimentService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + experiment.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() + val experiment = experimentService.update( ExperimentUpdateParams.builder() @@ -87,7 +100,11 @@ class ExperimentServiceTest { .datasetId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .datasetVersion("dataset_version") .description("description") - .metadata(ExperimentUpdateParams.Metadata.builder().build()) + .metadata( + ExperimentUpdateParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .name("name") .public_(true) .repoInfo( @@ -105,198 +122,208 @@ class ExperimentServiceTest { ) .build() ) - println(experiment) + experiment.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() - val response = experimentService.list(ExperimentListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = experimentService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() - val experiment = - experimentService.delete( - ExperimentDeleteParams.builder() - .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(experiment) + + val experiment = experimentService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + experiment.validate() } @Test - fun callFeedback() { + fun feedback() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() + val feedbackResponseSchema = experimentService.feedback( ExperimentFeedbackParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackExperimentItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackExperimentItem.Metadata.builder().build()) - .scores(FeedbackExperimentItem.Scores.builder().build()) - .source(FeedbackExperimentItem.Source.APP) - .build() - ) + .addFeedback( + FeedbackExperimentItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackExperimentItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackExperimentItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackExperimentItem.Source.APP) + .addTag("string") + .build() ) .build() ) - println(feedbackResponseSchema) + feedbackResponseSchema.validate() } @Test - fun callFetch() { + fun fetch() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() + val fetchExperimentEventsResponse = experimentService.fetch( ExperimentFetchParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() ) - println(fetchExperimentEventsResponse) + fetchExperimentEventsResponse.validate() } @Test - fun callFetchPost() { + fun fetchPost() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() + val fetchExperimentEventsResponse = experimentService.fetchPost( ExperimentFetchPostParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() ) - println(fetchExperimentEventsResponse) + fetchExperimentEventsResponse.validate() } @Test - fun callInsert() { + fun insert() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() + val insertEventsResponse = experimentService.insert( ExperimentInsertParams.builder() .experimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ExperimentInsertParams.Event.ofInsertExperimentEventReplace( - InsertExperimentEventReplace.builder() + .addEvent( + InsertExperimentEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertExperimentEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata( + InsertExperimentEvent.Metadata.builder().model("model").build() + ) + .metrics( + InsertExperimentEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertExperimentEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .datasetRecordId("dataset_record_id") - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata( - InsertExperimentEventReplace.Metadata.builder().build() - ) - .metrics( - InsertExperimentEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertExperimentEventReplace.Scores.builder().build()) - .spanAttributes( - InsertExperimentEventReplace.SpanAttributes.builder() - .name("name") - .type( - InsertExperimentEventReplace.SpanAttributes.Type.LLM - ) - .build() - ) - .tags(listOf("string")) + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertExperimentEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) .build() ) - ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() ) - println(insertEventsResponse) + insertEventsResponse.validate() } @Test - fun callSummarize() { + fun summarize() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val experimentService = client.experiments() + val summarizeExperimentResponse = experimentService.summarize( ExperimentSummarizeParams.builder() @@ -305,7 +332,7 @@ class ExperimentServiceTest { .summarizeScores(true) .build() ) - println(summarizeExperimentResponse) + summarizeExperimentResponse.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceTest.kt index 91a974ad..5cbf3a1c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/FunctionServiceTest.kt @@ -4,94 +4,101 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.FunctionListParams +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.FunctionCreateParams +import com.braintrustdata.api.models.FunctionInvokeParams +import com.braintrustdata.api.models.FunctionReplaceParams +import com.braintrustdata.api.models.FunctionUpdateParams +import com.braintrustdata.api.models.PromptData +import com.braintrustdata.api.models.PromptOptions import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class FunctionServiceTest { +internal class FunctionServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val functionService = client.functions() + val function = functionService.create( FunctionCreateParams.builder() .functionData( - FunctionCreateParams.FunctionData.ofPrompt( - FunctionCreateParams.FunctionData.Prompt.builder() - .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionCreateParams.FunctionData.Prompt.builder() + .type(FunctionCreateParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionSchema( FunctionCreateParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) .functionType(FunctionCreateParams.FunctionType.LLM) .origin( FunctionCreateParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionCreateParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params - .OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params - .OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -105,120 +112,116 @@ class FunctionServiceTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() ) - println(function) + function.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val functionService = client.functions() - val function = - functionService.retrieve( - FunctionRetrieveParams.builder() - .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(function) + + val function = functionService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + function.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val functionService = client.functions() + val function = functionService.update( FunctionUpdateParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") .functionData( - FunctionUpdateParams.FunctionData.ofPrompt( - FunctionUpdateParams.FunctionData.Prompt.builder() - .type(FunctionUpdateParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionUpdateParams.FunctionData.Prompt.builder() + .type(FunctionUpdateParams.FunctionData.Prompt.Type.PROMPT) + .build() ) .name("name") .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params - .OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params - .OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -232,203 +235,202 @@ class FunctionServiceTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() ) - println(function) + function.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val functionService = client.functions() - val response = functionService.list(FunctionListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = functionService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val functionService = client.functions() - val function = - functionService.delete( - FunctionDeleteParams.builder() - .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(function) + + val function = functionService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + function.validate() } @Test - fun callInvoke() { + fun invoke() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val functionService = client.functions() - val functionInvokeResponse = + + val response = functionService.invoke( FunctionInvokeParams.builder() .functionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .input(JsonNull.of()) - .messages( - listOf( - FunctionInvokeParams.Message.ofSystem( - FunctionInvokeParams.Message.System.builder() - .role(FunctionInvokeParams.Message.System.Role.SYSTEM) - .content("content") - .name("name") - .build() - ) - ) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .addMessage( + FunctionInvokeParams.Message.System.builder() + .role(FunctionInvokeParams.Message.System.Role.SYSTEM) + .content("content") + .name("name") + .build() + ) + .metadata( + FunctionInvokeParams.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() ) .mode(FunctionInvokeParams.Mode.AUTO) .parent( - FunctionInvokeParams.Parent.ofSpanParentStruct( - FunctionInvokeParams.Parent.SpanParentStruct.builder() - .objectId("object_id") - .objectType( - FunctionInvokeParams.Parent.SpanParentStruct.ObjectType - .PROJECT_LOGS - ) - .propagatedEvent( - FunctionInvokeParams.Parent.SpanParentStruct.PropagatedEvent - .builder() - .build() - ) - .rowIds( - FunctionInvokeParams.Parent.SpanParentStruct.RowIds.builder() - .id("id") - .rootSpanId("root_span_id") - .spanId("span_id") - .build() - ) - .build() - ) + FunctionInvokeParams.Parent.SpanParentStruct.builder() + .objectId("object_id") + .objectType( + FunctionInvokeParams.Parent.SpanParentStruct.ObjectType.PROJECT_LOGS + ) + .propagatedEvent( + FunctionInvokeParams.Parent.SpanParentStruct.PropagatedEvent + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .rowIds( + FunctionInvokeParams.Parent.SpanParentStruct.RowIds.builder() + .id("id") + .rootSpanId("root_span_id") + .spanId("span_id") + .build() + ) + .build() ) .stream(true) .version("version") .build() ) - println(functionInvokeResponse) + + response?.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val functionService = client.functions() + val function = functionService.replace( FunctionReplaceParams.builder() .functionData( - FunctionReplaceParams.FunctionData.ofPrompt( - FunctionReplaceParams.FunctionData.Prompt.builder() - .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) - .build() - ) + FunctionReplaceParams.FunctionData.Prompt.builder() + .type(FunctionReplaceParams.FunctionData.Prompt.Type.PROMPT) + .build() ) - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionSchema( FunctionReplaceParams.FunctionSchema.builder() - .parameters(JsonNull.of()) - .returns(JsonNull.of()) + .parameters(JsonValue.from(mapOf())) + .returns(JsonValue.from(mapOf())) .build() ) .functionType(FunctionReplaceParams.FunctionType.LLM) .origin( FunctionReplaceParams.Origin.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(FunctionReplaceParams.Origin.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .internal_(true) .build() ) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params - .OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params - .OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -442,35 +444,33 @@ class FunctionServiceTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() ) - println(function) + function.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/GroupServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/GroupServiceTest.kt index 197a6890..480533ef 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/GroupServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/GroupServiceTest.kt @@ -4,126 +4,125 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.GroupListParams +import com.braintrustdata.api.models.GroupCreateParams +import com.braintrustdata.api.models.GroupReplaceParams +import com.braintrustdata.api.models.GroupUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class GroupServiceTest { +internal class GroupServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val groupService = client.groups() + val group = groupService.create( GroupCreateParams.builder() - .name("name") + .name("x") .description("description") - .memberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .memberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() ) - println(group) + group.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val groupService = client.groups() - val group = - groupService.retrieve( - GroupRetrieveParams.builder() - .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(group) + + val group = groupService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + group.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val groupService = client.groups() + val group = groupService.update( GroupUpdateParams.builder() .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .addMemberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .addMemberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addAddMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addAddMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .name("name") - .removeMemberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .removeMemberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .name("x") + .addRemoveMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addRemoveMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) - println(group) + group.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val groupService = client.groups() - val response = groupService.list(GroupListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = groupService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val groupService = client.groups() - val group = - groupService.delete( - GroupDeleteParams.builder().groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - ) - println(group) + + val group = groupService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + group.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val groupService = client.groups() + val group = groupService.replace( GroupReplaceParams.builder() - .name("name") + .name("x") .description("description") - .memberGroups(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) - .memberUsers(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberGroup("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .addMemberUser("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() ) - println(group) + group.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceTest.kt index 17bcb9d2..c387c81b 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/OrganizationServiceTest.kt @@ -4,40 +4,36 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.OrganizationListParams +import com.braintrustdata.api.models.OrganizationUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class OrganizationServiceTest { +internal class OrganizationServiceTest { @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val organizationService = client.organizations() - val organization = - organizationService.retrieve( - OrganizationRetrieveParams.builder() - .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(organization) + + val organization = organizationService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + organization.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val organizationService = client.organizations() + val organization = organizationService.update( OrganizationUpdateParams.builder() @@ -49,38 +45,35 @@ class OrganizationServiceTest { .realtimeUrl("realtime_url") .build() ) - println(organization) + organization.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val organizationService = client.organizations() - val response = organizationService.list(OrganizationListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = organizationService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val organizationService = client.organizations() - val organization = - organizationService.delete( - OrganizationDeleteParams.builder() - .organizationId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(organization) + + val organization = organizationService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + organization.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceTest.kt index 2c6bf3c1..16d8e5ef 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectScoreServiceTest.kt @@ -4,55 +4,52 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.ProjectScoreListParams +import com.braintrustdata.api.models.OnlineScoreConfig +import com.braintrustdata.api.models.ProjectScoreCategory +import com.braintrustdata.api.models.ProjectScoreConfig +import com.braintrustdata.api.models.ProjectScoreCreateParams +import com.braintrustdata.api.models.ProjectScoreReplaceParams +import com.braintrustdata.api.models.ProjectScoreType +import com.braintrustdata.api.models.ProjectScoreUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class ProjectScoreServiceTest { +internal class ProjectScoreServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectScoreService = client.projectScores() + val projectScore = projectScoreService.create( ProjectScoreCreateParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) - .categories( - ProjectScoreCreateParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) - ) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type( - OnlineScoreConfig.Scorer.Function.Type - .FUNCTION - ) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -60,67 +57,55 @@ class ProjectScoreServiceTest { .description("description") .build() ) - println(projectScore) + projectScore.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectScoreService = client.projectScores() - val projectScore = - projectScoreService.retrieve( - ProjectScoreRetrieveParams.builder() - .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(projectScore) + + val projectScore = projectScoreService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + projectScore.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectScoreService = client.projectScores() + val projectScore = projectScoreService.update( ProjectScoreUpdateParams.builder() .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .categories( - ProjectScoreUpdateParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) - ) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type( - OnlineScoreConfig.Scorer.Function.Type - .FUNCTION - ) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -130,82 +115,71 @@ class ProjectScoreServiceTest { .scoreType(ProjectScoreType.SLIDER) .build() ) - println(projectScore) + projectScore.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectScoreService = client.projectScores() - val response = projectScoreService.list(ProjectScoreListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = projectScoreService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectScoreService = client.projectScores() - val projectScore = - projectScoreService.delete( - ProjectScoreDeleteParams.builder() - .projectScoreId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(projectScore) + + val projectScore = projectScoreService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + projectScore.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectScoreService = client.projectScores() + val projectScore = projectScoreService.replace( ProjectScoreReplaceParams.builder() .name("name") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .scoreType(ProjectScoreType.SLIDER) - .categories( - ProjectScoreReplaceParams.Categories.ofProjectScoreCategories( - listOf(ProjectScoreCategory.builder().name("name").value(42.23).build()) - ) + .categoriesOfCategorical( + listOf(ProjectScoreCategory.builder().name("name").value(0.0).build()) ) .config( ProjectScoreConfig.builder() - .destination(ProjectScoreConfig.Destination.EXPECTED) + .destination("destination") .multiSelect(true) .online( OnlineScoreConfig.builder() - .samplingRate(1.0) - .scorers( - listOf( - OnlineScoreConfig.Scorer.ofFunction( - OnlineScoreConfig.Scorer.Function.builder() - .id("id") - .type( - OnlineScoreConfig.Scorer.Function.Type - .FUNCTION - ) - .build() - ) - ) + .samplingRate(0.0) + .addScorer( + OnlineScoreConfig.Scorer.Function.builder() + .id("id") + .type(OnlineScoreConfig.Scorer.Function.Type.FUNCTION) + .build() ) .applyToRootSpan(true) - .applyToSpanNames(listOf("string")) + .addApplyToSpanName("string") .build() ) .build() @@ -213,7 +187,7 @@ class ProjectScoreServiceTest { .description("description") .build() ) - println(projectScore) + projectScore.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceTest.kt index b0793622..b179eb69 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectServiceTest.kt @@ -4,96 +4,105 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.ProjectListParams +import com.braintrustdata.api.models.ProjectCreateParams +import com.braintrustdata.api.models.ProjectSettings +import com.braintrustdata.api.models.ProjectUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class ProjectServiceTest { +internal class ProjectServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectService = client.projects() + val project = projectService.create( - ProjectCreateParams.builder().name("name").orgName("org_name").build() + ProjectCreateParams.builder().name("x").orgName("org_name").build() ) - println(project) + project.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectService = client.projects() - val project = - projectService.retrieve( - ProjectRetrieveParams.builder() - .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(project) + + val project = projectService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + project.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectService = client.projects() + val project = projectService.update( ProjectUpdateParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .name("name") - .settings(ProjectSettings.builder().comparisonKey("comparison_key").build()) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) .build() ) - println(project) + project.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectService = client.projects() - val response = projectService.list(ProjectListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = projectService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectService = client.projects() - val project = - projectService.delete( - ProjectDeleteParams.builder() - .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(project) + + val project = projectService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + project.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceTest.kt index bffa8967..4244bf41 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ProjectTagServiceTest.kt @@ -4,22 +4,24 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.ProjectTagListParams +import com.braintrustdata.api.models.ProjectTagCreateParams +import com.braintrustdata.api.models.ProjectTagReplaceParams +import com.braintrustdata.api.models.ProjectTagUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class ProjectTagServiceTest { +internal class ProjectTagServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectTagService = client.projectTags() + val projectTag = projectTagService.create( ProjectTagCreateParams.builder() @@ -29,36 +31,33 @@ class ProjectTagServiceTest { .description("description") .build() ) - println(projectTag) + projectTag.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectTagService = client.projectTags() - val projectTag = - projectTagService.retrieve( - ProjectTagRetrieveParams.builder() - .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(projectTag) + + val projectTag = projectTagService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + projectTag.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectTagService = client.projectTags() + val projectTag = projectTagService.update( ProjectTagUpdateParams.builder() @@ -68,49 +67,47 @@ class ProjectTagServiceTest { .name("name") .build() ) - println(projectTag) + projectTag.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectTagService = client.projectTags() - val response = projectTagService.list(ProjectTagListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = projectTagService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectTagService = client.projectTags() - val projectTag = - projectTagService.delete( - ProjectTagDeleteParams.builder() - .projectTagId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(projectTag) + + val projectTag = projectTagService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + projectTag.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val projectTagService = client.projectTags() + val projectTag = projectTagService.replace( ProjectTagReplaceParams.builder() @@ -120,7 +117,7 @@ class ProjectTagServiceTest { .description("description") .build() ) - println(projectTag) + projectTag.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/PromptServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/PromptServiceTest.kt index bb5693ea..3544ab5c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/PromptServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/PromptServiceTest.kt @@ -4,73 +4,81 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.PromptListParams +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.PromptCreateParams +import com.braintrustdata.api.models.PromptData +import com.braintrustdata.api.models.PromptOptions +import com.braintrustdata.api.models.PromptReplaceParams +import com.braintrustdata.api.models.PromptUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class PromptServiceTest { +internal class PromptServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val promptService = client.prompts() + val prompt = promptService.create( PromptCreateParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionType(PromptCreateParams.FunctionType.LLM) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params - .OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params - .OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -84,64 +92,59 @@ class PromptServiceTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() ) - println(prompt) + prompt.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val promptService = client.prompts() - val prompt = - promptService.retrieve( - PromptRetrieveParams.builder() - .promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(prompt) + + val prompt = promptService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + prompt.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val promptService = client.prompts() + val prompt = promptService.update( PromptUpdateParams.builder() @@ -151,46 +154,49 @@ class PromptServiceTest { .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params - .OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params - .OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -204,129 +210,128 @@ class PromptServiceTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) .slug("slug") - .tags(listOf("string")) + .addTag("string") .build() ) - println(prompt) + prompt.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val promptService = client.prompts() - val response = promptService.list(PromptListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = promptService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val promptService = client.prompts() - val prompt = - promptService.delete( - PromptDeleteParams.builder() - .promptId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - ) - println(prompt) + + val prompt = promptService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + prompt.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val promptService = client.prompts() + val prompt = promptService.replace( PromptReplaceParams.builder() - .name("name") + .name("x") .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .slug("slug") + .slug("x") .description("description") .functionType(PromptReplaceParams.FunctionType.LLM) .promptData( PromptData.builder() .options( - PromptData.Options.builder() + PromptOptions.builder() .model("model") .params( - PromptData.Options.Params.ofOpenAIModelParams( - PromptData.Options.Params.OpenAIModelParams.builder() - .frequencyPenalty(42.23) - .functionCall( - PromptData.Options.Params.OpenAIModelParams - .FunctionCall - .ofAuto( - PromptData.Options.Params - .OpenAIModelParams - .FunctionCall - .Auto - .AUTO - ) - ) - .maxTokens(42.23) - .n(42.23) - .presencePenalty(42.23) - .responseFormat( - PromptData.Options.Params.OpenAIModelParams - .ResponseFormat - .builder() - .type( - PromptData.Options.Params - .OpenAIModelParams - .ResponseFormat - .Type - .JSON_OBJECT - ) - .build() - ) - .stop(listOf("string")) - .temperature(42.23) - .toolChoice(ToolChoice.ofAuto(ToolChoice.Auto.AUTO)) - .topP(42.23) - .useCache(true) - .build() - ) + PromptOptions.Params.OpenAIModelParams.builder() + .frequencyPenalty(0.0) + .functionCall( + PromptOptions.Params.OpenAIModelParams.FunctionCall + .UnionMember0 + .AUTO + ) + .maxCompletionTokens(0.0) + .maxTokens(0.0) + .n(0.0) + .presencePenalty(0.0) + .reasoningEffort( + PromptOptions.Params.OpenAIModelParams + .ReasoningEffort + .LOW + ) + .responseFormat( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .builder() + .type( + PromptOptions.Params.OpenAIModelParams + .ResponseFormat + .JsonObject + .Type + .JSON_OBJECT + ) + .build() + ) + .addStop("string") + .temperature(0.0) + .toolChoice( + PromptOptions.Params.OpenAIModelParams.ToolChoice + .UnionMember0 + .AUTO + ) + .topP(0.0) + .useCache(true) + .build() ) .position("position") .build() @@ -340,35 +345,33 @@ class PromptServiceTest { ) .parser( PromptData.Parser.builder() - .choiceScores(PromptData.Parser.ChoiceScores.builder().build()) + .choiceScores( + PromptData.Parser.ChoiceScores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) .type(PromptData.Parser.Type.LLM_CLASSIFIER) .useCot(true) .build() ) .prompt( - PromptData.Prompt.ofCompletion( - PromptData.Prompt.Completion.builder() - .content("content") - .type(PromptData.Prompt.Completion.Type.COMPLETION) - .build() - ) + PromptData.Prompt.Completion.builder() + .content("content") + .type(PromptData.Prompt.Completion.Type.COMPLETION) + .build() ) - .toolFunctions( - listOf( - PromptData.ToolFunction.ofFunction( - PromptData.ToolFunction.Function.builder() - .id("id") - .type(PromptData.ToolFunction.Function.Type.FUNCTION) - .build() - ) - ) + .addToolFunction( + PromptData.ToolFunction.Function.builder() + .id("id") + .type(PromptData.ToolFunction.Function.Type.FUNCTION) + .build() ) .build() ) - .tags(listOf("string")) + .addTag("string") .build() ) - println(prompt) + prompt.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/RoleServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/RoleServiceTest.kt index 20cdf599..3bab9b17 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/RoleServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/RoleServiceTest.kt @@ -4,166 +4,147 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.RoleListParams +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.Permission +import com.braintrustdata.api.models.RoleCreateParams +import com.braintrustdata.api.models.RoleReplaceParams +import com.braintrustdata.api.models.RoleUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class RoleServiceTest { +internal class RoleServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val roleService = client.roles() + val role = roleService.create( RoleCreateParams.builder() - .name("name") + .name("x") .description("description") - .memberPermissions( - listOf( - RoleCreateParams.MemberPermission.builder() - .permission(RoleCreateParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleCreateParams.MemberPermission.RestrictObjectType - .ORGANIZATION - ) - .build() - ) + .addMemberPermission( + RoleCreateParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .memberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() ) - println(role) + role.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val roleService = client.roles() - val role = - roleService.retrieve( - RoleRetrieveParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - ) - println(role) + + val role = roleService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + role.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val roleService = client.roles() + val role = roleService.update( RoleUpdateParams.builder() .roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .addMemberPermissions( - listOf( - RoleUpdateParams.AddMemberPermission.builder() - .permission(RoleUpdateParams.AddMemberPermission.Permission.CREATE) - .restrictObjectType( - RoleUpdateParams.AddMemberPermission.RestrictObjectType - .ORGANIZATION - ) - .build() - ) + .addAddMemberPermission( + RoleUpdateParams.AddMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .addMemberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addAddMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .description("description") - .name("name") - .removeMemberPermissions( - listOf( - RoleUpdateParams.RemoveMemberPermission.builder() - .permission( - RoleUpdateParams.RemoveMemberPermission.Permission.CREATE - ) - .restrictObjectType( - RoleUpdateParams.RemoveMemberPermission.RestrictObjectType - .ORGANIZATION - ) - .build() - ) + .name("x") + .addRemoveMemberPermission( + RoleUpdateParams.RemoveMemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .removeMemberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addRemoveMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) - println(role) + role.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val roleService = client.roles() - val response = roleService.list(RoleListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = roleService.list() + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val roleService = client.roles() - val role = - roleService.delete( - RoleDeleteParams.builder().roleId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - ) - println(role) + + val role = roleService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + role.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val roleService = client.roles() + val role = roleService.replace( RoleReplaceParams.builder() - .name("name") + .name("x") .description("description") - .memberPermissions( - listOf( - RoleReplaceParams.MemberPermission.builder() - .permission(RoleReplaceParams.MemberPermission.Permission.CREATE) - .restrictObjectType( - RoleReplaceParams.MemberPermission.RestrictObjectType - .ORGANIZATION - ) - .build() - ) + .addMemberPermission( + RoleReplaceParams.MemberPermission.builder() + .permission(Permission.CREATE) + .restrictObjectType(AclObjectType.ORGANIZATION) + .build() ) - .memberRoles(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addMemberRole("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .orgName("org_name") .build() ) - println(role) + role.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/SpanIframeServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/SpanIframeServiceTest.kt new file mode 100644 index 00000000..1d2c51ae --- /dev/null +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/SpanIframeServiceTest.kt @@ -0,0 +1,126 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.services.blocking + +import com.braintrustdata.api.TestServerExtension +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient +import com.braintrustdata.api.models.SpanIframeCreateParams +import com.braintrustdata.api.models.SpanIframeReplaceParams +import com.braintrustdata.api.models.SpanIframeUpdateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class SpanIframeServiceTest { + + @Test + fun create() { + val client = + BraintrustOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeService = client.spanIframes() + + val spanIFrame = + spanIframeService.create( + SpanIframeCreateParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + ) + + spanIFrame.validate() + } + + @Test + fun retrieve() { + val client = + BraintrustOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeService = client.spanIframes() + + val spanIFrame = spanIframeService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + spanIFrame.validate() + } + + @Test + fun update() { + val client = + BraintrustOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeService = client.spanIframes() + + val spanIFrame = + spanIframeService.update( + SpanIframeUpdateParams.builder() + .spanIframeId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .description("description") + .name("name") + .postMessage(true) + .url("url") + .build() + ) + + spanIFrame.validate() + } + + @Test + fun list() { + val client = + BraintrustOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeService = client.spanIframes() + + val page = spanIframeService.list() + + page.response().validate() + } + + @Test + fun delete() { + val client = + BraintrustOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeService = client.spanIframes() + + val spanIFrame = spanIframeService.delete("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + spanIFrame.validate() + } + + @Test + fun replace() { + val client = + BraintrustOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val spanIframeService = client.spanIframes() + + val spanIFrame = + spanIframeService.replace( + SpanIframeReplaceParams.builder() + .name("name") + .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("url") + .description("description") + .postMessage(true) + .build() + ) + + spanIFrame.validate() + } +} diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceTest.kt index ab277bdc..de7c1385 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/TopLevelServiceTest.kt @@ -4,25 +4,21 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class TopLevelServiceTest { +internal class TopLevelServiceTest { @Test - fun callHelloWorld() { + fun helloWorld() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val topLevelService = client.topLevel() - val topLevelHelloWorldResponse = - topLevelService.helloWorld(TopLevelHelloWorldParams.builder().build()) - println(topLevelHelloWorldResponse) - assertThat(topLevelHelloWorldResponse).isNotBlank() + + topLevelService.helloWorld() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/UserServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/UserServiceTest.kt index 24f732e2..6376460c 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/UserServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/UserServiceTest.kt @@ -4,40 +4,37 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* -import com.braintrustdata.api.models.UserListParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class UserServiceTest { +internal class UserServiceTest { @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val userService = client.users() - val user = - userService.retrieve( - UserRetrieveParams.builder().userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - ) - println(user) + + val user = userService.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + user.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val userService = client.users() - val response = userService.list(UserListParams.builder().build()) - println(response) - response.objects().forEach { it.validate() } + + val page = userService.list() + + page.response().validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ViewServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ViewServiceTest.kt index 5eefd68b..4019925d 100755 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ViewServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/ViewServiceTest.kt @@ -4,37 +4,57 @@ package com.braintrustdata.api.services.blocking import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.ViewCreateParams +import com.braintrustdata.api.models.ViewData +import com.braintrustdata.api.models.ViewDataSearch +import com.braintrustdata.api.models.ViewDeleteParams import com.braintrustdata.api.models.ViewListParams +import com.braintrustdata.api.models.ViewOptions +import com.braintrustdata.api.models.ViewReplaceParams +import com.braintrustdata.api.models.ViewRetrieveParams +import com.braintrustdata.api.models.ViewUpdateParams import java.time.OffsetDateTime import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class ViewServiceTest { +internal class ViewServiceTest { @Test - fun callCreate() { + fun create() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val viewService = client.views() + val view = viewService.create( ViewCreateParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewCreateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .viewType(ViewCreateParams.ViewType.PROJECTS) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -42,60 +62,73 @@ class ViewServiceTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() ) .build() ) - println(view) + view.validate() } @Test - fun callRetrieve() { + fun retrieve() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val viewService = client.views() + val view = viewService.retrieve( ViewRetrieveParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewRetrieveParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() ) - println(view) + view.validate() } @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val viewService = client.views() + val view = viewService.update( ViewUpdateParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewUpdateParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .name("name") .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -103,10 +136,10 @@ class ViewServiceTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() @@ -114,70 +147,84 @@ class ViewServiceTest { .viewType(ViewUpdateParams.ViewType.PROJECTS) .build() ) - println(view) + view.validate() } @Test - fun callList() { + fun list() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val viewService = client.views() - val response = + + val page = viewService.list( ViewListParams.builder() .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewListParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() ) - println(response) - response.objects().forEach { it.validate() } + + page.response().validate() } @Test - fun callDelete() { + fun delete() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val viewService = client.views() + val view = viewService.delete( ViewDeleteParams.builder() .viewId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewDeleteParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .build() ) - println(view) + view.validate() } @Test - fun callReplace() { + fun replace() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val viewService = client.views() + val view = viewService.replace( ViewReplaceParams.builder() .name("name") .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .objectType(ViewReplaceParams.ObjectType.ORGANIZATION) + .objectType(AclObjectType.ORGANIZATION) .viewType(ViewReplaceParams.ViewType.PROJECTS) .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) .options( ViewOptions.builder() - .columnOrder(listOf("string")) - .columnSizing(ViewOptions.ColumnSizing.builder().build()) - .columnVisibility(ViewOptions.ColumnVisibility.builder().build()) + .addColumnOrder("string") + .columnSizing( + ViewOptions.ColumnSizing.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .columnVisibility( + ViewOptions.ColumnVisibility.builder() + .putAdditionalProperty("foo", JsonValue.from(true)) + .build() + ) + .grouping("grouping") + .layout("layout") + .rowHeight("rowHeight") .build() ) .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") @@ -185,17 +232,17 @@ class ViewServiceTest { ViewData.builder() .search( ViewDataSearch.builder() - .filter(listOf(JsonNull.of())) - .match(listOf(JsonNull.of())) - .sort(listOf(JsonNull.of())) - .tag(listOf(JsonNull.of())) + .addFilter(JsonValue.from(mapOf())) + .addMatch(JsonValue.from(mapOf())) + .addSort(JsonValue.from(mapOf())) + .addTag(JsonValue.from(mapOf())) .build() ) .build() ) .build() ) - println(view) + view.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceTest.kt index 6f12d171..cf30ad12 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/organizations/MemberServiceTest.kt @@ -4,32 +4,33 @@ package com.braintrustdata.api.services.blocking.organizations import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.models.* +import com.braintrustdata.api.models.OrganizationMemberUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class MemberServiceTest { +internal class MemberServiceTest { @Test - fun callUpdate() { + fun update() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val memberService = client.organizations().members() + val patchOrganizationMembersOutput = memberService.update( OrganizationMemberUpdateParams.builder() .inviteUsers( OrganizationMemberUpdateParams.InviteUsers.builder() - .emails(listOf("string")) + .addEmail("string") .groupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .groupIds(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .groupName("group_name") - .groupNames(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addGroupName("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .sendInviteEmails(true) .build() ) @@ -37,13 +38,13 @@ class MemberServiceTest { .orgName("org_name") .removeUsers( OrganizationMemberUpdateParams.RemoveUsers.builder() - .emails(listOf("string")) - .ids(listOf("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")) + .addEmail("string") + .addId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .build() ) .build() ) - println(patchOrganizationMembersOutput) + patchOrganizationMembersOutput.validate() } } diff --git a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceTest.kt b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceTest.kt index 21c25964..d0ccaad0 100644 --- a/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceTest.kt +++ b/braintrust-kotlin-core/src/test/kotlin/com/braintrustdata/api/services/blocking/projects/LogServiceTest.kt @@ -4,161 +4,181 @@ package com.braintrustdata.api.services.blocking.projects import com.braintrustdata.api.TestServerExtension import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient -import com.braintrustdata.api.core.JsonNull -import com.braintrustdata.api.models.* +import com.braintrustdata.api.core.JsonValue +import com.braintrustdata.api.models.FeedbackProjectLogsItem +import com.braintrustdata.api.models.InsertProjectLogsEvent +import com.braintrustdata.api.models.ObjectReference +import com.braintrustdata.api.models.ProjectLogFeedbackParams +import com.braintrustdata.api.models.ProjectLogFetchParams +import com.braintrustdata.api.models.ProjectLogFetchPostParams +import com.braintrustdata.api.models.ProjectLogInsertParams +import com.braintrustdata.api.models.SpanAttributes +import com.braintrustdata.api.models.SpanType import java.time.OffsetDateTime import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) -class LogServiceTest { +internal class LogServiceTest { @Test - fun callFeedback() { + fun feedback() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val logService = client.projects().logs() + val feedbackResponseSchema = logService.feedback( ProjectLogFeedbackParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .feedback( - listOf( - FeedbackProjectLogsItem.builder() - .id("id") - .comment("comment") - .expected(JsonNull.of()) - .metadata(FeedbackProjectLogsItem.Metadata.builder().build()) - .scores(FeedbackProjectLogsItem.Scores.builder().build()) - .source(FeedbackProjectLogsItem.Source.APP) - .build() - ) + .addFeedback( + FeedbackProjectLogsItem.builder() + .id("id") + .comment("comment") + .expected(JsonValue.from(mapOf())) + .metadata( + FeedbackProjectLogsItem.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .scores( + FeedbackProjectLogsItem.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) + .build() + ) + .source(FeedbackProjectLogsItem.Source.APP) + .addTag("string") + .build() ) .build() ) - println(feedbackResponseSchema) + feedbackResponseSchema.validate() } @Test - fun callFetch() { + fun fetch() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val logService = client.projects().logs() + val fetchProjectLogsEventsResponse = logService.fetch( ProjectLogFetchParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() ) - println(fetchProjectLogsEventsResponse) + fetchProjectLogsEventsResponse.validate() } @Test - fun callFetchPost() { + fun fetchPost() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val logService = client.projects().logs() + val fetchProjectLogsEventsResponse = logService.fetchPost( ProjectLogFetchPostParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") .cursor("cursor") - .filters( - listOf( - PathLookupFilter.builder() - .path(listOf("string")) - .type(PathLookupFilter.Type.PATH_LOOKUP) - .value(JsonNull.of()) - .build() - ) - ) - .limit(123L) + .limit(0L) .maxRootSpanId("max_root_span_id") .maxXactId("max_xact_id") .version("version") .build() ) - println(fetchProjectLogsEventsResponse) + fetchProjectLogsEventsResponse.validate() } @Test - fun callInsert() { + fun insert() { val client = BraintrustOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() val logService = client.projects().logs() + val insertEventsResponse = logService.insert( ProjectLogInsertParams.builder() .projectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .events( - listOf( - ProjectLogInsertParams.Event.ofInsertProjectLogsEventReplace( - InsertProjectLogsEventReplace.builder() + .addEvent( + InsertProjectLogsEvent.builder() + .id("id") + ._isMerge(true) + .addMergePath(listOf("string")) + ._objectDelete(true) + ._parentId("_parent_id") + .context( + InsertProjectLogsEvent.Context.builder() + .callerFilename("caller_filename") + .callerFunctionname("caller_functionname") + .callerLineno(0L) + .build() + ) + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .error(JsonValue.from(mapOf())) + .expected(JsonValue.from(mapOf())) + .input(JsonValue.from(mapOf())) + .metadata( + InsertProjectLogsEvent.Metadata.builder().model("model").build() + ) + .metrics( + InsertProjectLogsEvent.Metrics.builder() + .callerFilename(JsonValue.from(mapOf())) + .callerFunctionname(JsonValue.from(mapOf())) + .callerLineno(JsonValue.from(mapOf())) + .completionTokens(0L) + .end(0.0) + .promptTokens(0L) + .start(0.0) + .tokens(0L) + .build() + ) + .origin( + ObjectReference.builder() .id("id") - ._isMerge(true) - ._objectDelete(true) - ._parentId("_parent_id") - .context( - InsertProjectLogsEventReplace.Context.builder() - .callerFilename("caller_filename") - .callerFunctionname("caller_functionname") - .callerLineno(123L) - .build() - ) - .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .error(JsonNull.of()) - .expected(JsonNull.of()) - .input(JsonNull.of()) - .metadata( - InsertProjectLogsEventReplace.Metadata.builder().build() - ) - .metrics( - InsertProjectLogsEventReplace.Metrics.builder() - .completionTokens(123L) - .end(42.23) - .promptTokens(123L) - .start(42.23) - .tokens(123L) - .build() - ) - .output(JsonNull.of()) - .scores(InsertProjectLogsEventReplace.Scores.builder().build()) - .spanAttributes( - InsertProjectLogsEventReplace.SpanAttributes.builder() - .name("name") - .type( - InsertProjectLogsEventReplace.SpanAttributes.Type - .LLM - ) - .build() - ) - .tags(listOf("string")) + ._xactId("_xact_id") + .objectId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .objectType(ObjectReference.ObjectType.EXPERIMENT) + .created("created") + .build() + ) + .output(JsonValue.from(mapOf())) + .rootSpanId("root_span_id") + .scores( + InsertProjectLogsEvent.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from(0)) .build() ) - ) + .spanAttributes( + SpanAttributes.builder().name("name").type(SpanType.LLM).build() + ) + .spanId("span_id") + .addSpanParent("string") + .addTag("string") + .build() ) .build() ) - println(insertEventsResponse) + insertEventsResponse.validate() } } diff --git a/braintrust-kotlin-example/build.gradle.kts b/braintrust-kotlin-example/build.gradle.kts new file mode 100644 index 00000000..7c3e1e40 --- /dev/null +++ b/braintrust-kotlin-example/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("braintrust.kotlin") + application +} + +dependencies { + implementation(project(":braintrust-kotlin")) +} + +application { + // Use `./gradlew :braintrust-kotlin-example:run` to run `Main` + // Use `./gradlew :braintrust-kotlin-example:run -Pexample=Something` to run `SomethingExample` + mainClass = "com.braintrustdata.api.example.${ + if (project.hasProperty("example")) + "${project.property("example")}ExampleKt" + else + "MainKt" + }" +} diff --git a/braintrust-kotlin-proguard-test/build.gradle.kts b/braintrust-kotlin-proguard-test/build.gradle.kts new file mode 100644 index 00000000..59421bc7 --- /dev/null +++ b/braintrust-kotlin-proguard-test/build.gradle.kts @@ -0,0 +1,101 @@ +plugins { + id("braintrust.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(":braintrust-kotlin")) + 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("../braintrust-kotlin-core/src/main/resources/META-INF/proguard/braintrust-kotlin-core.pro") +} + +val testProGuard by tasks.registering(JavaExec::class) { + group = "verification" + dependsOn(proguardJar) + notCompatibleWithConfigurationCache("ProGuard") + + mainClass.set("com.braintrustdata.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", "../braintrust-kotlin-core/src/main/resources/META-INF/proguard/braintrust-kotlin-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.braintrustdata.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/braintrust-kotlin-proguard-test/src/test/kotlin/com/braintrustdata/api/proguard/ProGuardCompatibilityTest.kt b/braintrust-kotlin-proguard-test/src/test/kotlin/com/braintrustdata/api/proguard/ProGuardCompatibilityTest.kt new file mode 100644 index 00000000..9bb3c189 --- /dev/null +++ b/braintrust-kotlin-proguard-test/src/test/kotlin/com/braintrustdata/api/proguard/ProGuardCompatibilityTest.kt @@ -0,0 +1,130 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.braintrustdata.api.proguard + +import com.braintrustdata.api.client.okhttp.BraintrustOkHttpClient +import com.braintrustdata.api.core.jsonMapper +import com.braintrustdata.api.models.AclObjectType +import com.braintrustdata.api.models.Project +import com.braintrustdata.api.models.ProjectListPageResponse +import com.braintrustdata.api.models.ProjectSettings +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +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/braintrust-kotlin-core.pro" + ) + + assertThat(rulesFile).isNotNull() + } + + @Test + fun client() { + val client = BraintrustOkHttpClient.builder().apiKey("My API Key").build() + + assertThat(client).isNotNull() + assertThat(client.topLevel()).isNotNull() + assertThat(client.projects()).isNotNull() + assertThat(client.experiments()).isNotNull() + assertThat(client.datasets()).isNotNull() + assertThat(client.prompts()).isNotNull() + assertThat(client.roles()).isNotNull() + assertThat(client.groups()).isNotNull() + assertThat(client.acls()).isNotNull() + assertThat(client.users()).isNotNull() + assertThat(client.projectScores()).isNotNull() + assertThat(client.projectTags()).isNotNull() + assertThat(client.spanIframes()).isNotNull() + assertThat(client.functions()).isNotNull() + assertThat(client.views()).isNotNull() + assertThat(client.organizations()).isNotNull() + assertThat(client.apiKeys()).isNotNull() + assertThat(client.aiSecrets()).isNotNull() + assertThat(client.envVars()).isNotNull() + assertThat(client.evals()).isNotNull() + } + + @Test + fun projectListPageResponseRoundtrip() { + val jsonMapper = jsonMapper() + val projectListPageResponse = + ProjectListPageResponse.builder() + .addObject( + Project.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .name("name") + .orgId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .created(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .deletedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) + .settings( + ProjectSettings.builder() + .baselineExperimentId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .comparisonKey("comparison_key") + .addSpanFieldOrder( + ProjectSettings.SpanFieldOrder.builder() + .columnId("column_id") + .objectType("object_type") + .position("position") + .layout(ProjectSettings.SpanFieldOrder.Layout.FULL) + .build() + ) + .build() + ) + .userId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + ) + .build() + + val roundtrippedProjectListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(projectListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedProjectListPageResponse).isEqualTo(projectListPageResponse) + } + + @Test + fun aclObjectTypeRoundtrip() { + val jsonMapper = jsonMapper() + val aclObjectType = AclObjectType.ORGANIZATION + + val roundtrippedAclObjectType = + jsonMapper.readValue( + jsonMapper.writeValueAsString(aclObjectType), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAclObjectType).isEqualTo(aclObjectType) + } +} diff --git a/braintrust-kotlin-proguard-test/test.pro b/braintrust-kotlin-proguard-test/test.pro new file mode 100644 index 00000000..a55227f1 --- /dev/null +++ b/braintrust-kotlin-proguard-test/test.pro @@ -0,0 +1,9 @@ +# Specify the entrypoint where ProGuard starts to determine what's reachable. +-keep class com.braintrustdata.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/braintrust-kotlin/build.gradle.kts b/braintrust-kotlin/build.gradle.kts index 8f31ae52..564a3aae 100755 --- a/braintrust-kotlin/build.gradle.kts +++ b/braintrust-kotlin/build.gradle.kts @@ -6,3 +6,24 @@ plugins { dependencies { api(project(":braintrust-kotlin-client-okhttp")) } + +// Redefine `dokkaHtml` 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("dokkaHtml").configure { + actions.clear() + + val dokkaHtmlCollector = rootProject.tasks["dokkaHtmlCollector"] + dependsOn(dokkaHtmlCollector) + + val outputDirectory = project.layout.buildDirectory.dir("dokka/html") + doLast { + copy { + from(dokkaHtmlCollector.outputs.files) + into(outputDirectory) + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + } + + outputs.dir(outputDirectory) +} diff --git a/build.gradle.kts b/build.gradle.kts index ce5f3ab1..b5b3c935 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,36 @@ plugins { + id("org.jetbrains.dokka") version "2.0.0" +} +repositories { + mavenCentral() } allprojects { group = "com.braintrustdata.api" - version = "0.3.0" // x-release-please-version + version = "0.4.0" // x-release-please-version } +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 `dokkaHtmlCollector` and `dokkaJavadocJar` tasks +tasks.named("dokkaHtmlCollector").configure { + subprojects.flatMap { it.tasks } + .filter { it.project.name != "braintrust-kotlin" && it.name == "dokkaJavadocJar" } + .forEach { mustRunAfter(it) } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 493cb327..c6dc92ec 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,6 +1,6 @@ plugins { `kotlin-dsl` - kotlin("jvm") version "1.9.22" + kotlin("jvm") version "1.9.20" id("com.vanniktech.maven.publish") version "0.28.0" } @@ -10,7 +10,6 @@ repositories { } dependencies { - implementation("com.diffplug.spotless:spotless-plugin-gradle:6.25.0") - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23") + 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/braintrust.java.gradle.kts b/buildSrc/src/main/kotlin/braintrust.java.gradle.kts index 53e63304..70fc33f4 100755 --- a/buildSrc/src/main/kotlin/braintrust.java.gradle.kts +++ b/buildSrc/src/main/kotlin/braintrust.java.gradle.kts @@ -1,31 +1,20 @@ -import com.diffplug.gradle.spotless.SpotlessExtension import org.gradle.api.tasks.testing.logging.TestExceptionFormat -import com.vanniktech.maven.publish.JavaLibrary -import com.vanniktech.maven.publish.JavadocJar -import com.vanniktech.maven.publish.MavenPublishBaseExtension -import com.vanniktech.maven.publish.SonatypeHost plugins { `java-library` - id("com.diffplug.spotless") } repositories { mavenCentral() } -configure { - java { - importOrder() - removeUnusedImports() - palantirJavaFormat() - } -} - java { toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(21)) } + + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } tasks.withType().configureEach { @@ -42,10 +31,97 @@ tasks.named("jar") { } } -tasks.named("test") { +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/braintrust.kotlin.gradle.kts b/buildSrc/src/main/kotlin/braintrust.kotlin.gradle.kts index 267e3576..832189a3 100755 --- a/buildSrc/src/main/kotlin/braintrust.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/braintrust.kotlin.gradle.kts @@ -1,28 +1,106 @@ -import com.diffplug.gradle.spotless.SpotlessExtension -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import com.vanniktech.maven.publish.* +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { id("braintrust.java") kotlin("jvm") } +repositories { + mavenCentral() +} + kotlin { jvmToolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(21)) } -} -configure { - kotlin { - ktfmt().kotlinlangStyle() + 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 { - kotlinOptions { - allWarningsAsErrors = true - freeCompilerArgs = listOf("-Xjvm-default=all", "-Xjdk-release=1.8") - jvmTarget = "1.8" +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/braintrust.publish.gradle.kts b/buildSrc/src/main/kotlin/braintrust.publish.gradle.kts index e6c76652..80b70bea 100755 --- a/buildSrc/src/main/kotlin/braintrust.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/braintrust.publish.gradle.kts @@ -1,10 +1,5 @@ -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.register -import org.gradle.kotlin.dsl.get -import com.vanniktech.maven.publish.JavaLibrary import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.KotlinJvm import com.vanniktech.maven.publish.MavenPublishBaseExtension import com.vanniktech.maven.publish.SonatypeHost @@ -25,7 +20,13 @@ configure { signAllPublications() publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) - this.coordinates(project.group.toString(), project.name, project.version.toString()) + coordinates(project.group.toString(), project.name, project.version.toString()) + configure( + KotlinJvm( + javadocJar = JavadocJar.Dokka("dokkaHtml"), + sourcesJar = true, + ) + ) pom { name.set("Braintrust API") @@ -41,7 +42,7 @@ configure { developers { developer { name.set("Braintrust") - email.set("info-test@braintrustdata.com") + email.set("info@braintrustdata.com") } } @@ -52,3 +53,7 @@ configure { } } } + +tasks.withType().configureEach { + isZip64 = true +} diff --git a/gradle.properties b/gradle.properties index a3bc58f2..6680f9ce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,18 @@ org.gradle.caching=true -org.gradle.jvmargs=-Xmx4g +org.gradle.configuration-cache=true org.gradle.parallel=true -kotlin.daemon.jvmargs=-Xmx4g +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 index e6441136..a4b76b95 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a..cea7a793 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42..f3b75f3b 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# 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/. @@ -84,7 +86,7 @@ done # 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 "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +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 diff --git a/gradlew.bat b/gradlew.bat index 7101f8e4..9b42019c 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @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 ########################################################################## diff --git a/scripts/build b/scripts/build new file mode 100755 index 00000000..f4063482 --- /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/format b/scripts/format index c6239fab..9e294b97 100755 --- a/scripts/format +++ b/scripts/format @@ -4,5 +4,10 @@ set -e cd "$(dirname "$0")/.." -echo "==> Running spotlessApply" -./gradlew --build-cache --parallel --no-daemon spotlessApply +if command -v ktfmt &> /dev/null; then + echo "==> Running ktfmt" + find . -name "*.kt" -not -path "./buildSrc/build/*" -print0 | xargs -0 -r ktfmt --kotlinlang-style "$@" +else + echo "==> Running gradlew format" + ./gradlew format +fi diff --git a/scripts/lint b/scripts/lint index 58753d0b..5837798c 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,5 +4,10 @@ set -e cd "$(dirname "$0")/.." -echo "==> Build classes" -./gradlew --build-cache --parallel --no-daemon build testClasses -x test +if command -v ktfmt &> /dev/null; then + echo "==> Checking ktfmt" + ./scripts/format --dry-run --set-exit-if-changed +else + echo "==> Running gradlew lint" + ./gradlew lint +fi diff --git a/scripts/mock b/scripts/mock index d2814ae6..0b28f6ea 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,7 +21,7 @@ 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.8.5 -- prism mock "$URL" &> .prism.log & + 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" @@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" fi diff --git a/scripts/test b/scripts/test index 72ed0333..047bc1db 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! prism_is_running ; then 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=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" echo exit 1 @@ -53,4 +53,4 @@ else fi echo "==> Running tests" -./gradlew --build-cache --parallel --no-daemon test +./gradlew test "$@" diff --git a/settings.gradle.kts b/settings.gradle.kts index 807ae0d1..1b1bfbf7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,14 @@ rootProject.name = "braintrust-kotlin-root" -include("braintrust-kotlin") -include("braintrust-kotlin-client-okhttp") -include("braintrust-kotlin-core") -include("braintrust-kotlin-example") +val projectNames = rootDir.listFiles() + ?.asSequence() + .orEmpty() + .filter { file -> + file.isDirectory && + file.name.startsWith("braintrust-kotlin") && + file.listFiles()?.asSequence().orEmpty().any { it.name == "build.gradle.kts" } + } + .map { it.name } + .toList() +println("projects: $projectNames") +projectNames.forEach { include(it) }