diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml new file mode 100644 index 0000000..ccc3eaf --- /dev/null +++ b/.github/workflows/publish-sonatype.yml @@ -0,0 +1,39 @@ +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to Sonatype in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/OmniStack-sh/omnistack-kotlin/actions/workflows/publish-sonatype.yml +name: Publish Sonatype +on: + workflow_dispatch: + + release: + types: [published] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: | + 8 + 17 + cache: gradle + + - name: Set up Gradle + uses: gradle/gradle-build-action@v2 + + - name: Publish to Sonatype + run: | + ./gradlew --parallel --no-daemon publish + env: + SONATYPE_USERNAME: ${{ secrets.OMNISTACK_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.OMNISTACK_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY_ID: ${{ secrets.OMNISTACK_SONATYPE_GPG_SIGNING_KEY_ID || secrets.GPG_SIGNING_KEY_ID }} + GPG_SIGNING_KEY: ${{ secrets.OMNISTACK_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.OMNISTACK_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000..fb9ce8a --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,25 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'OmniStack-sh/omnistack-kotlin' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + SONATYPE_USERNAME: ${{ secrets.OMNISTACK_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.OMNISTACK_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY_ID: ${{ secrets.OMNISTACK_SONATYPE_GPG_SIGNING_KEY_ID || secrets.GPG_SIGNING_KEY_ID }} + GPG_SIGNING_KEY: ${{ secrets.OMNISTACK_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.OMNISTACK_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..ba6c348 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.1.0-alpha.1" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e4f008c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +## 0.1.0-alpha.1 (2024-11-12) + +Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/OmniStack-sh/omnistack-kotlin/compare/v0.0.1-alpha.0...v0.1.0-alpha.1) + +### Features + +* **api:** api update ([60c35dc](https://github.com/OmniStack-sh/omnistack-kotlin/commit/60c35dcb8e1f6cbf7535d086678752e086d843b5)) +* **api:** api update ([#1](https://github.com/OmniStack-sh/omnistack-kotlin/issues/1)) ([3df1f83](https://github.com/OmniStack-sh/omnistack-kotlin/commit/3df1f836b96e209484104a2722f6ee47d5f28686)) + + +### Chores + +* rebuild project due to codegen change ([#10](https://github.com/OmniStack-sh/omnistack-kotlin/issues/10)) ([fa93e56](https://github.com/OmniStack-sh/omnistack-kotlin/commit/fa93e56380e178d78c59907f58634aa6b05d57d9)) +* rebuild project due to codegen change ([#3](https://github.com/OmniStack-sh/omnistack-kotlin/issues/3)) ([aa6fca3](https://github.com/OmniStack-sh/omnistack-kotlin/commit/aa6fca3c9f263f10db2919c13ce7fb009b7a9687)) +* rebuild project due to codegen change ([#4](https://github.com/OmniStack-sh/omnistack-kotlin/issues/4)) ([c60d81b](https://github.com/OmniStack-sh/omnistack-kotlin/commit/c60d81b1c42f8b05166ae0cc92c33709ac6563c8)) +* rebuild project due to codegen change ([#5](https://github.com/OmniStack-sh/omnistack-kotlin/issues/5)) ([265f2f1](https://github.com/OmniStack-sh/omnistack-kotlin/commit/265f2f14899c5c2a4a41e67dd3cf5a287eff5661)) +* rebuild project due to codegen change ([#6](https://github.com/OmniStack-sh/omnistack-kotlin/issues/6)) ([d36ecb0](https://github.com/OmniStack-sh/omnistack-kotlin/commit/d36ecb0ebc4ab5642a3075e546cd9d725f05e4dc)) +* rebuild project due to codegen change ([#7](https://github.com/OmniStack-sh/omnistack-kotlin/issues/7)) ([440588a](https://github.com/OmniStack-sh/omnistack-kotlin/commit/440588a390cdab04358b59a54a4bc6a9d1a8a7a4)) +* rebuild project due to codegen change ([#8](https://github.com/OmniStack-sh/omnistack-kotlin/issues/8)) ([3f862cb](https://github.com/OmniStack-sh/omnistack-kotlin/commit/3f862cbf289344d7d624d98f364ac079ccf81a79)) +* rebuild project due to codegen change ([#9](https://github.com/OmniStack-sh/omnistack-kotlin/issues/9)) ([1d0d7aa](https://github.com/OmniStack-sh/omnistack-kotlin/commit/1d0d7aa95fa103c409dfaf0bc935b0bd22948cf9)) diff --git a/README.md b/README.md index 0fb40b2..9b82399 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,10 @@ The REST API documentation can be foundĀ on [docs.omnistack.sh](https://docs.omn #### Gradle + + ```kotlin -implementation("com.omnistack.api:omnistack-kotlin:0.0.1-alpha.0") +implementation("com.omnistack.api:omnistack-kotlin:0.1.0-alpha.1") ``` #### Maven @@ -28,10 +30,12 @@ implementation("com.omnistack.api:omnistack-kotlin:0.0.1-alpha.0") com.omnistack.api omnistack-kotlin - 0.0.1-alpha.0 + 0.1.0-alpha.1 ``` + + ### Configure the client Use `OmnistackOkHttpClient.builder()` to configure the client. At a minimum you need to set `.apiKey()`: @@ -75,7 +79,7 @@ import com.omnistack.api.models.CompletionCreateParams import com.omnistack.api.models.CompletionCreateResponse val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model("string") .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .build() val completion = client.completions().create(params) @@ -218,7 +222,7 @@ This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) con We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. -We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/omnistack-kotlin/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/OmniStack-sh/omnistack-kotlin/issues) with questions, bugs, or suggestions. ## Requirements diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..4c8289d --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${SONATYPE_USERNAME}" ]; then + errors+=("The OMNISTACK_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 OMNISTACK_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 OMNISTACK_SONATYPE_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 OMNISTACK_SONATYPE_GPG_SIGNING_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" diff --git a/build.gradle.kts b/build.gradle.kts index 20f1dff..87f3d7e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { allprojects { group = "com.omnistack.api" - version = "0.0.1-alpha.0" + version = "0.1.0-alpha.1" // x-release-please-version } nexusPublishing { diff --git a/buildSrc/src/main/kotlin/omnistack.publish.gradle.kts b/buildSrc/src/main/kotlin/omnistack.publish.gradle.kts index 962da7a..11bcb64 100644 --- a/buildSrc/src/main/kotlin/omnistack.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/omnistack.publish.gradle.kts @@ -33,9 +33,9 @@ configure { } scm { - connection.set("scm:git:git://github.com/stainless-sdks/omnistack-kotlin.git") - developerConnection.set("scm:git:git://github.com/stainless-sdks/omnistack-kotlin.git") - url.set("https://github.com/stainless-sdks/omnistack-kotlin") + connection.set("scm:git:git://github.com/OmniStack-sh/omnistack-kotlin.git") + developerConnection.set("scm:git:git://github.com/OmniStack-sh/omnistack-kotlin.git") + url.set("https://github.com/OmniStack-sh/omnistack-kotlin") } versionMapping { diff --git a/omnistack-kotlin-client-okhttp/build.gradle.kts b/omnistack-kotlin-client-okhttp/build.gradle.kts index 84287a6..afacb16 100644 --- a/omnistack-kotlin-client-okhttp/build.gradle.kts +++ b/omnistack-kotlin-client-okhttp/build.gradle.kts @@ -6,11 +6,9 @@ plugins { dependencies { api(project(":omnistack-kotlin-core")) - implementation("com.google.guava:guava:33.0.0-jre") implementation("com.squareup.okhttp3:okhttp: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/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OkHttpClient.kt b/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OkHttpClient.kt index e58b8e2..b214b57 100644 --- a/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OkHttpClient.kt +++ b/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OkHttpClient.kt @@ -1,8 +1,7 @@ package com.omnistack.api.client.okhttp -import com.google.common.collect.ListMultimap -import com.google.common.collect.MultimapBuilder import com.omnistack.api.core.RequestOptions +import com.omnistack.api.core.http.Headers import com.omnistack.api.core.http.HttpClient import com.omnistack.api.core.http.HttpMethod import com.omnistack.api.core.http.HttpRequest @@ -16,7 +15,6 @@ import java.time.Duration import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.Call import okhttp3.Callback -import okhttp3.Headers import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType @@ -80,13 +78,15 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val private fun HttpRequest.toRequest(): Request { var body: RequestBody? = body?.toRequestBody() - // OkHttpClient always requires a request body for PUT and POST methods + // OkHttpClient always requires a request body for PUT and POST methods. if (body == null && (method == HttpMethod.PUT || method == HttpMethod.POST)) { 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.header(name, it) } + } return builder.build() } @@ -98,7 +98,9 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val val builder = baseUrl.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 +110,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,33 +124,20 @@ 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 { @@ -166,7 +147,7 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val class Builder { private var baseUrl: HttpUrl? = null - // default timeout is 1 minute + // The default timeout is 1 minute. private var timeout: Duration = Duration.ofSeconds(60) private var proxy: Proxy? = null @@ -176,8 +157,8 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } - fun build(): OkHttpClient { - return OkHttpClient( + fun build(): OkHttpClient = + OkHttpClient( okhttp3.OkHttpClient.Builder() .connectTimeout(timeout) .readTimeout(timeout) @@ -187,7 +168,6 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val .build(), checkNotNull(baseUrl) { "`baseUrl` is required but was not set" }, ) - } } private suspend fun Call.executeAsync(): Response = diff --git a/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClient.kt b/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClient.kt index c686a0e..d0e8a6f 100644 --- a/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClient.kt +++ b/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClient.kt @@ -6,6 +6,8 @@ import com.fasterxml.jackson.databind.json.JsonMapper import com.omnistack.api.client.OmnistackClient import com.omnistack.api.client.OmnistackClientImpl import com.omnistack.api.core.ClientOptions +import com.omnistack.api.core.http.Headers +import com.omnistack.api.core.http.QueryParams import java.net.Proxy import java.time.Clock import java.time.Duration @@ -23,7 +25,7 @@ class OmnistackOkHttpClient private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var baseUrl: String = ClientOptions.PRODUCTION_URL - // default timeout for client is 1 minute + // The default timeout for the client is 1 minute. private var timeout: Duration = Duration.ofSeconds(60) private var proxy: Proxy? = null @@ -36,6 +38,8 @@ class OmnistackOkHttpClient private constructor() { fun clock(clock: Clock) = apply { clientOptions.clock(clock) } + fun headers(headers: Headers) = apply { clientOptions.headers(headers) } + fun headers(headers: Map>) = apply { clientOptions.headers(headers) } @@ -46,11 +50,73 @@ class OmnistackOkHttpClient 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 replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + clientOptions.replaceAllHeaders(headers) + } + + fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) } + + fun removeAllHeaders(names: Set) = apply { clientOptions.removeAllHeaders(names) } + + fun queryParams(queryParams: QueryParams) = apply { clientOptions.queryParams(queryParams) } + + fun queryParams(queryParams: Map>) = apply { + clientOptions.queryParams(queryParams) + } + + fun putQueryParam(key: String, value: String) = apply { + clientOptions.putQueryParam(key, value) + } + + fun putQueryParams(key: String, values: Iterable) = apply { + clientOptions.putQueryParams(key, values) + } + + fun putAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun putAllQueryParams(queryParams: Map>) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun replaceQueryParams(key: String, value: String) = apply { + clientOptions.replaceQueryParams(key, value) + } + + fun replaceQueryParams(key: String, values: Iterable) = apply { + clientOptions.replaceQueryParams(key, values) + } + + fun replaceAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun replaceAllQueryParams(queryParams: Map>) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun removeQueryParams(key: String) = apply { clientOptions.removeQueryParams(key) } + + fun removeAllQueryParams(keys: Set) = apply { + clientOptions.removeAllQueryParams(keys) + } fun timeout(timeout: Duration) = apply { this.timeout = timeout } @@ -66,8 +132,8 @@ class OmnistackOkHttpClient private constructor() { fun fromEnv() = apply { clientOptions.fromEnv() } - fun build(): OmnistackClient { - return OmnistackClientImpl( + fun build(): OmnistackClient = + OmnistackClientImpl( clientOptions .httpClient( OkHttpClient.builder() @@ -78,6 +144,5 @@ class OmnistackOkHttpClient private constructor() { ) .build() ) - } } } diff --git a/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClientAsync.kt b/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClientAsync.kt index 9f17683..6ab1ec7 100644 --- a/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClientAsync.kt +++ b/omnistack-kotlin-client-okhttp/src/main/kotlin/com/omnistack/api/client/okhttp/OmnistackOkHttpClientAsync.kt @@ -6,6 +6,8 @@ import com.fasterxml.jackson.databind.json.JsonMapper import com.omnistack.api.client.OmnistackClientAsync import com.omnistack.api.client.OmnistackClientAsyncImpl import com.omnistack.api.core.ClientOptions +import com.omnistack.api.core.http.Headers +import com.omnistack.api.core.http.QueryParams import java.net.Proxy import java.time.Clock import java.time.Duration @@ -23,7 +25,7 @@ class OmnistackOkHttpClientAsync private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var baseUrl: String = ClientOptions.PRODUCTION_URL - // default timeout for client is 1 minute + // The default timeout for the client is 1 minute. private var timeout: Duration = Duration.ofSeconds(60) private var proxy: Proxy? = null @@ -36,6 +38,8 @@ class OmnistackOkHttpClientAsync private constructor() { fun clock(clock: Clock) = apply { clientOptions.clock(clock) } + fun headers(headers: Headers) = apply { clientOptions.headers(headers) } + fun headers(headers: Map>) = apply { clientOptions.headers(headers) } @@ -46,11 +50,73 @@ class OmnistackOkHttpClientAsync 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 replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + clientOptions.replaceAllHeaders(headers) + } + + fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) } + + fun removeAllHeaders(names: Set) = apply { clientOptions.removeAllHeaders(names) } + + fun queryParams(queryParams: QueryParams) = apply { clientOptions.queryParams(queryParams) } + + fun queryParams(queryParams: Map>) = apply { + clientOptions.queryParams(queryParams) + } + + fun putQueryParam(key: String, value: String) = apply { + clientOptions.putQueryParam(key, value) + } + + fun putQueryParams(key: String, values: Iterable) = apply { + clientOptions.putQueryParams(key, values) + } + + fun putAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun putAllQueryParams(queryParams: Map>) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun replaceQueryParams(key: String, value: String) = apply { + clientOptions.replaceQueryParams(key, value) + } + + fun replaceQueryParams(key: String, values: Iterable) = apply { + clientOptions.replaceQueryParams(key, values) + } + + fun replaceAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun replaceAllQueryParams(queryParams: Map>) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun removeQueryParams(key: String) = apply { clientOptions.removeQueryParams(key) } + + fun removeAllQueryParams(keys: Set) = apply { + clientOptions.removeAllQueryParams(keys) + } fun timeout(timeout: Duration) = apply { this.timeout = timeout } @@ -66,8 +132,8 @@ class OmnistackOkHttpClientAsync private constructor() { fun fromEnv() = apply { clientOptions.fromEnv() } - fun build(): OmnistackClientAsync { - return OmnistackClientAsyncImpl( + fun build(): OmnistackClientAsync = + OmnistackClientAsyncImpl( clientOptions .httpClient( OkHttpClient.builder() @@ -78,6 +144,5 @@ class OmnistackOkHttpClientAsync private constructor() { ) .build() ) - } } } diff --git a/omnistack-kotlin-core/build.gradle.kts b/omnistack-kotlin-core/build.gradle.kts index dc40a5e..6025409 100644 --- a/omnistack-kotlin-core/build.gradle.kts +++ b/omnistack-kotlin-core/build.gradle.kts @@ -6,7 +6,6 @@ plugins { 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") implementation("com.fasterxml.jackson.core:jackson-annotations:2.14.3") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.3") @@ -20,8 +19,6 @@ dependencies { testImplementation(project(":omnistack-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") } diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClient.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClient.kt index 7e0e1e8..8f1caca 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClient.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClient.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.client import com.omnistack.api.models.* diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsync.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsync.kt index 7be4583..40a86dc 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsync.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsync.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.client import com.omnistack.api.models.* diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsyncImpl.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsyncImpl.kt index 769a258..9004073 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsyncImpl.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientAsyncImpl.kt @@ -3,6 +3,7 @@ package com.omnistack.api.client import com.omnistack.api.core.ClientOptions +import com.omnistack.api.core.getPackageVersion import com.omnistack.api.models.* import com.omnistack.api.services.async.* @@ -11,12 +12,21 @@ constructor( private val clientOptions: ClientOptions, ) : OmnistackClientAsync { + 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: OmnistackClient by lazy { OmnistackClientImpl(clientOptions) } - private val chats: ChatServiceAsync by lazy { ChatServiceAsyncImpl(clientOptions) } + private val chats: ChatServiceAsync by lazy { ChatServiceAsyncImpl(clientOptionsWithUserAgent) } private val completions: CompletionServiceAsync by lazy { - CompletionServiceAsyncImpl(clientOptions) + CompletionServiceAsyncImpl(clientOptionsWithUserAgent) } override fun sync(): OmnistackClient = sync diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientImpl.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientImpl.kt index 32366df..9310c15 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientImpl.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/client/OmnistackClientImpl.kt @@ -3,6 +3,7 @@ package com.omnistack.api.client import com.omnistack.api.core.ClientOptions +import com.omnistack.api.core.getPackageVersion import com.omnistack.api.models.* import com.omnistack.api.services.blocking.* @@ -11,11 +12,22 @@ constructor( private val clientOptions: ClientOptions, ) : OmnistackClient { + 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: OmnistackClientAsync by lazy { OmnistackClientAsyncImpl(clientOptions) } - private val chats: ChatService by lazy { ChatServiceImpl(clientOptions) } + private val chats: ChatService by lazy { ChatServiceImpl(clientOptionsWithUserAgent) } - private val completions: CompletionService by lazy { CompletionServiceImpl(clientOptions) } + private val completions: CompletionService by lazy { + CompletionServiceImpl(clientOptionsWithUserAgent) + } override fun async(): OmnistackClientAsync = async diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/ClientOptions.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/ClientOptions.kt index 7605cfc..b0edf9c 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/ClientOptions.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/ClientOptions.kt @@ -3,24 +3,29 @@ package com.omnistack.api.core import com.fasterxml.jackson.databind.json.JsonMapper -import com.google.common.collect.ArrayListMultimap -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers import com.omnistack.api.core.http.HttpClient +import com.omnistack.api.core.http.PhantomReachableClosingHttpClient +import com.omnistack.api.core.http.QueryParams import com.omnistack.api.core.http.RetryingHttpClient import java.time.Clock class ClientOptions private constructor( + private val originalHttpClient: HttpClient, val httpClient: HttpClient, val jsonMapper: JsonMapper, val clock: Clock, val baseUrl: String, - val apiKey: String, - val headers: ListMultimap, - val queryParams: ListMultimap, + val headers: Headers, + val queryParams: QueryParams, val responseValidation: Boolean, + val maxRetries: Int, + val apiKey: String, ) { + fun toBuilder() = Builder().from(this) + companion object { const val PRODUCTION_URL = "https://api.omnistack.sh/openai/v1" @@ -33,60 +38,114 @@ private constructor( class Builder { private var httpClient: HttpClient? = null - private var jsonMapper: JsonMapper? = null + private var jsonMapper: JsonMapper = jsonMapper() private var clock: Clock = Clock.systemUTC() private var baseUrl: String = PRODUCTION_URL - private var headers: MutableMap> = mutableMapOf() - private var queryParams: MutableMap> = mutableMapOf() + private var headers: Headers.Builder = Headers.builder() + private var queryParams: QueryParams.Builder = QueryParams.builder() private var responseValidation: Boolean = false private var maxRetries: Int = 2 private var apiKey: String? = null + internal fun from(clientOptions: ClientOptions) = apply { + httpClient = clientOptions.originalHttpClient + jsonMapper = clientOptions.jsonMapper + clock = clientOptions.clock + baseUrl = clientOptions.baseUrl + headers = clientOptions.headers.toBuilder() + queryParams = clientOptions.queryParams.toBuilder() + responseValidation = clientOptions.responseValidation + maxRetries = clientOptions.maxRetries + apiKey = clientOptions.apiKey + } + fun httpClient(httpClient: HttpClient) = apply { this.httpClient = httpClient } fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper } + fun clock(clock: Clock) = apply { this.clock = clock } + fun baseUrl(baseUrl: String) = apply { this.baseUrl = baseUrl } - fun clock(clock: Clock) = apply { this.clock = clock } + 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 replaceQueryParams(key: String, value: String) = apply { + queryParams.replace(key, value) } - fun removeQueryParam(name: String) = apply { this.queryParams.put(name, mutableListOf()) } + 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 responseValidation(responseValidation: Boolean) = apply { this.responseValidation = responseValidation @@ -102,33 +161,40 @@ private constructor( checkNotNull(httpClient) { "`httpClient` is required but was not set" } checkNotNull(apiKey) { "`apiKey` is required but was not set" } - 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( - RetryingHttpClient.builder() - .httpClient(httpClient!!) - .clock(clock) - .maxRetries(maxRetries) - .build(), - jsonMapper ?: jsonMapper(), + httpClient!!, + PhantomReachableClosingHttpClient( + RetryingHttpClient.builder() + .httpClient(httpClient!!) + .clock(clock) + .maxRetries(maxRetries) + .build() + ), + jsonMapper, clock, baseUrl, - apiKey!!, - headers.toUnmodifiable(), - queryParams.toUnmodifiable(), + headers.build(), + queryParams.build(), responseValidation, + maxRetries, + apiKey!!, ) } } diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/PhantomReachable.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/PhantomReachable.kt new file mode 100644 index 0000000..db2978d --- /dev/null +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/PhantomReachable.kt @@ -0,0 +1,45 @@ +@file:JvmName("PhantomReachable") + +package com.omnistack.api.core + +import com.omnistack.api.errors.OmnistackException +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?.let { it(observed, closeable::close) } +} + +private val closeWhenPhantomReachable: ((Any, AutoCloseable) -> 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, closeable -> + try { + cleanerRegister.invoke(cleanerObject, observed, Runnable { closeable.close() }) + } catch (e: ReflectiveOperationException) { + if (e is InvocationTargetException) { + when (val cause = e.cause) { + is RuntimeException, + is Error -> throw cause + } + } + throw OmnistackException("Unexpected reflective invocation failure", e) + } + } + } catch (e: ReflectiveOperationException) { + // We're running Java 8, which has no Cleaner. + null + } +} diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Utils.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Utils.kt index b236402..9e05f7e 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Utils.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Utils.kt @@ -2,55 +2,21 @@ package com.omnistack.api.core -import com.google.common.collect.ImmutableListMultimap -import com.google.common.collect.ListMultimap -import com.google.common.collect.Multimaps import com.omnistack.api.errors.OmnistackInvalidDataException import java.util.Collections +import java.util.SortedMap -internal fun T?.getOrThrow(name: String): T { - if (this == null) { - throw OmnistackInvalidDataException("'${name}' is not present") - } +internal fun T?.getOrThrow(name: String): T = + this ?: throw OmnistackInvalidDataException("`${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()) Collections.emptyMap() else Collections.unmodifiableMap(toMap()) - return Collections.unmodifiableList(this) -} - -internal fun Map.toUnmodifiable(): Map { - if (isEmpty()) { - return Collections.emptyMap() - } - - return Collections.unmodifiableMap(this) -} - -internal fun ListMultimap.toUnmodifiable(): ListMultimap { - if (isEmpty()) { - return ImmutableListMultimap.of() - } - - return Multimaps.unmodifiableListMultimap(this) -} - -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 OmnistackInvalidDataException("Could not find $header header") - } - return value.get() -} +internal fun , V> SortedMap.toImmutable(): SortedMap = + if (isEmpty()) Collections.emptySortedMap() + else Collections.unmodifiableSortedMap(toSortedMap(comparator())) internal interface Enum diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Values.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Values.kt index 32ef01a..ad76968 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Values.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/Values.kt @@ -138,6 +138,8 @@ sealed class JsonField { // 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) : @@ -383,7 +385,7 @@ private constructor( override fun toString() = values.toString() companion object { - @JsonCreator fun of(values: List) = JsonArray(values.toUnmodifiable()) + @JsonCreator fun of(values: List) = JsonArray(values.toImmutable()) } } @@ -407,7 +409,7 @@ private constructor( override fun toString() = values.toString() companion object { - @JsonCreator fun of(values: Map) = JsonObject(values.toUnmodifiable()) + @JsonCreator fun of(values: Map) = JsonObject(values.toImmutable()) } } @@ -473,9 +475,8 @@ internal constructor( } } - override fun toString(): String { - return "MultipartFormValue(name='$name', contentType=$contentType, filename=$filename, value=${valueToString()})" - } + override fun toString(): String = + "MultipartFormValue{name=$name, contentType=$contentType, filename=$filename, value=${valueToString()}}" private fun valueToString(): String = when (value) { diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/handlers/ErrorHandler.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/handlers/ErrorHandler.kt index 65e8849..98ff312 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/handlers/ErrorHandler.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/handlers/ErrorHandler.kt @@ -3,7 +3,7 @@ package com.omnistack.api.core.handlers import com.fasterxml.jackson.databind.json.JsonMapper -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers import com.omnistack.api.core.http.HttpResponse import com.omnistack.api.core.http.HttpResponse.Handler import com.omnistack.api.errors.BadRequestException @@ -114,7 +114,7 @@ private fun HttpResponse.buffered(): HttpResponse { return object : HttpResponse { override fun statusCode(): Int = this@buffered.statusCode() - override fun headers(): ListMultimap = this@buffered.headers() + override fun headers(): Headers = this@buffered.headers() override fun body(): InputStream = ByteArrayInputStream(body) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/Headers.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/Headers.kt new file mode 100644 index 0000000..79b172e --- /dev/null +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/Headers.kt @@ -0,0 +1,88 @@ +package com.omnistack.api.core.http + +import com.omnistack.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 { + + private val map: MutableMap> = + TreeMap(String.CASE_INSENSITIVE_ORDER) + private var size: Int = 0 + + 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/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpRequest.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpRequest.kt index 694ae1b..94ba53d 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpRequest.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpRequest.kt @@ -1,23 +1,21 @@ package com.omnistack.api.core.http -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.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.toImmutable class HttpRequest private constructor( val method: HttpMethod, val url: 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, url=$url, pathSegments=$pathSegments, headers=$headers, queryParams=$queryParams, body=$body}" companion object { fun builder() = Builder() @@ -27,65 +25,119 @@ private constructor( private var method: HttpMethod? = null private var url: String? = null - private var pathSegments: MutableList = ArrayList() - private var queryParams: ListMultimap = ArrayListMultimap.create() + 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 + url = request.url + 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 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, + pathSegments.toImmutable(), + headers.build(), + queryParams.build(), body, ) } diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpResponse.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpResponse.kt index 636079c..75da421 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpResponse.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/HttpResponse.kt @@ -1,6 +1,5 @@ package com.omnistack.api.core.http -import com.google.common.collect.ListMultimap import java.io.InputStream import java.lang.AutoCloseable @@ -8,7 +7,7 @@ interface HttpResponse : AutoCloseable { fun statusCode(): Int - fun headers(): ListMultimap + fun headers(): Headers fun body(): InputStream diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/PhantomReachableClosingHttpClient.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/PhantomReachableClosingHttpClient.kt new file mode 100644 index 0000000..e525da5 --- /dev/null +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/PhantomReachableClosingHttpClient.kt @@ -0,0 +1,20 @@ +package com.omnistack.api.core.http + +import com.omnistack.api.core.RequestOptions +import com.omnistack.api.core.closeWhenPhantomReachable + +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/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/QueryParams.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/QueryParams.kt new file mode 100644 index 0000000..9ed8488 --- /dev/null +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/QueryParams.kt @@ -0,0 +1,82 @@ +package com.omnistack.api.core.http + +import com.omnistack.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 { + + private val map: MutableMap> = mutableMapOf() + private var size: Int = 0 + + 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/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/RetryingHttpClient.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/RetryingHttpClient.kt index 3ae47f9..3da3df5 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/RetryingHttpClient.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/core/http/RetryingHttpClient.kt @@ -1,5 +1,3 @@ -@file:JvmSynthetic - package com.omnistack.api.core.http import com.omnistack.api.core.RequestOptions @@ -35,21 +33,22 @@ private constructor( 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 } @@ -76,21 +75,22 @@ 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 } @@ -109,33 +109,33 @@ private constructor( } } - override fun close() { - httpClient.close() - } + override fun close() = httpClient.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,11 +155,10 @@ private constructor( } } - private fun shouldRetry(throwable: Throwable): Boolean { + private fun shouldRetry(throwable: Throwable): Boolean = // Only retry IOException and OmnistackIoException, other exceptions are not intended to be // retried. - return throwable is IOException || throwable is OmnistackIoException - } + throwable is IOException || throwable is OmnistackIoException private fun getRetryBackoffMillis(retries: Int, response: HttpResponse?): Duration { // About the Retry-After header: @@ -168,11 +167,11 @@ private constructor( ?.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( diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/BadRequestException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/BadRequestException.kt index 000fb43..70bd0f6 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/BadRequestException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/BadRequestException.kt @@ -1,9 +1,9 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class BadRequestException( - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(400, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/InternalServerException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/InternalServerException.kt index e4e7e3f..dd86ec2 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/InternalServerException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/InternalServerException.kt @@ -1,10 +1,10 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class InternalServerException( statusCode: Int, - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(statusCode, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/NotFoundException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/NotFoundException.kt index 1f59241..d01343b 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/NotFoundException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/NotFoundException.kt @@ -1,9 +1,9 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class NotFoundException( - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(404, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackError.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackError.kt index 0835fba..86a0e4b 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackError.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackError.kt @@ -7,20 +7,16 @@ import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.toImmutable import java.util.Objects @JsonDeserialize(builder = OmnistackError.Builder::class) @NoAutoDetect class OmnistackError -constructor( - private val additionalProperties: Map, +private constructor( + @JsonAnyGetter val additionalProperties: Map, ) { - @JsonAnyGetter fun additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder() - override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -35,31 +31,41 @@ constructor( override fun toString() = "OmnistackError{additionalProperties=$additionalProperties}" + fun toBuilder() = Builder().from(this) + companion object { - @JvmStatic fun builder() = Builder() + fun builder() = Builder() } class Builder { private var additionalProperties: MutableMap = mutableMapOf() - fun from(error: OmnistackError) = apply { additionalProperties(error.additionalProperties) } + internal fun from(omnistackError: OmnistackError) = apply { + additionalProperties = omnistackError.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(): OmnistackError = OmnistackError(additionalProperties.toUnmodifiable()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + fun build(): OmnistackError = OmnistackError(additionalProperties.toImmutable()) } } diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackServiceException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackServiceException.kt index 78db09a..f0cfeb2 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackServiceException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/OmnistackServiceException.kt @@ -1,10 +1,10 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers abstract class OmnistackServiceException( private val statusCode: Int, - private val headers: ListMultimap, + private val headers: Headers, private val body: String, private val error: OmnistackError, message: String = "$statusCode: $error", @@ -13,7 +13,7 @@ abstract class OmnistackServiceException( fun statusCode(): Int = statusCode - fun headers(): ListMultimap = headers + fun headers(): Headers = headers fun body(): String = body diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/PermissionDeniedException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/PermissionDeniedException.kt index 47f5c22..9690173 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/PermissionDeniedException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/PermissionDeniedException.kt @@ -1,9 +1,9 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class PermissionDeniedException( - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(403, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/RateLimitException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/RateLimitException.kt index d6726c9..42fd346 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/RateLimitException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/RateLimitException.kt @@ -1,9 +1,9 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class RateLimitException( - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(429, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnauthorizedException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnauthorizedException.kt index 8bda2cb..95bd850 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnauthorizedException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnauthorizedException.kt @@ -1,9 +1,9 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class UnauthorizedException( - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(401, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnexpectedStatusCodeException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnexpectedStatusCodeException.kt index 831bdab..8b8dffb 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnexpectedStatusCodeException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnexpectedStatusCodeException.kt @@ -1,10 +1,10 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class UnexpectedStatusCodeException( statusCode: Int, - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(statusCode, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnprocessableEntityException.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnprocessableEntityException.kt index ccaa926..567e323 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnprocessableEntityException.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/errors/UnprocessableEntityException.kt @@ -1,9 +1,9 @@ package com.omnistack.api.errors -import com.google.common.collect.ListMultimap +import com.omnistack.api.core.http.Headers class UnprocessableEntityException( - headers: ListMultimap, + headers: Headers, body: String, error: OmnistackError, ) : OmnistackServiceException(422, headers, body, error) diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateParams.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateParams.kt index 19bc2d4..97f90c1 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateParams.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateParams.kt @@ -22,7 +22,9 @@ import com.omnistack.api.core.JsonMissing import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect import com.omnistack.api.core.getOrThrow -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.http.Headers +import com.omnistack.api.core.http.QueryParams +import com.omnistack.api.core.toImmutable import com.omnistack.api.errors.OmnistackInvalidDataException import com.omnistack.api.models.* import java.util.Objects @@ -53,8 +55,8 @@ constructor( private val topLogprobs: Long?, private val topP: Double?, private val user: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) { @@ -136,9 +138,9 @@ constructor( ) } - internal fun getQueryParams(): Map> = additionalQueryParams + internal fun getHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + internal fun getQueryParams(): QueryParams = additionalQueryParams @JsonDeserialize(builder = ChatCompletionCreateBody.Builder::class) @NoAutoDetect @@ -709,11 +711,11 @@ constructor( fun build(): ChatCompletionCreateBody = ChatCompletionCreateBody( checkNotNull(messages) { "`messages` is required but was not set" } - .toUnmodifiable(), + .toImmutable(), checkNotNull(model) { "`model` is required but was not set" }, frequencyPenalty, functionCall, - functions?.toUnmodifiable(), + functions?.toImmutable(), logitBias, logprobs, maxCompletionTokens, @@ -729,11 +731,11 @@ constructor( streamOptions, temperature, toolChoice, - tools?.toUnmodifiable(), + tools?.toImmutable(), topLogprobs, topP, user, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -758,9 +760,9 @@ constructor( "ChatCompletionCreateBody{messages=$messages, model=$model, frequencyPenalty=$frequencyPenalty, functionCall=$functionCall, functions=$functions, logitBias=$logitBias, logprobs=$logprobs, maxCompletionTokens=$maxCompletionTokens, maxTokens=$maxTokens, n=$n, parallelToolCalls=$parallelToolCalls, presencePenalty=$presencePenalty, responseFormat=$responseFormat, seed=$seed, serviceTier=$serviceTier, stop=$stop, stream=$stream, streamOptions=$streamOptions, temperature=$temperature, toolChoice=$toolChoice, tools=$tools, topLogprobs=$topLogprobs, topP=$topP, user=$user, additionalProperties=$additionalProperties}" } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun _additionalHeaders(): Headers = additionalHeaders - fun _additionalHeaders(): Map> = additionalHeaders + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -769,15 +771,15 @@ constructor( return true } - return /* spotless:off */ other is ChatCompletionCreateParams && this.messages == other.messages && this.model == other.model && this.frequencyPenalty == other.frequencyPenalty && this.functionCall == other.functionCall && this.functions == other.functions && this.logitBias == other.logitBias && this.logprobs == other.logprobs && this.maxCompletionTokens == other.maxCompletionTokens && this.maxTokens == other.maxTokens && this.n == other.n && this.parallelToolCalls == other.parallelToolCalls && this.presencePenalty == other.presencePenalty && this.responseFormat == other.responseFormat && this.seed == other.seed && this.serviceTier == other.serviceTier && this.stop == other.stop && this.stream == other.stream && this.streamOptions == other.streamOptions && this.temperature == other.temperature && this.toolChoice == other.toolChoice && this.tools == other.tools && this.topLogprobs == other.topLogprobs && this.topP == other.topP && this.user == other.user && this.additionalQueryParams == other.additionalQueryParams && this.additionalHeaders == other.additionalHeaders && this.additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ + return /* spotless:off */ other is ChatCompletionCreateParams && this.messages == other.messages && this.model == other.model && this.frequencyPenalty == other.frequencyPenalty && this.functionCall == other.functionCall && this.functions == other.functions && this.logitBias == other.logitBias && this.logprobs == other.logprobs && this.maxCompletionTokens == other.maxCompletionTokens && this.maxTokens == other.maxTokens && this.n == other.n && this.parallelToolCalls == other.parallelToolCalls && this.presencePenalty == other.presencePenalty && this.responseFormat == other.responseFormat && this.seed == other.seed && this.serviceTier == other.serviceTier && this.stop == other.stop && this.stream == other.stream && this.streamOptions == other.streamOptions && this.temperature == other.temperature && this.toolChoice == other.toolChoice && this.tools == other.tools && this.topLogprobs == other.topLogprobs && this.topP == other.topP && this.user == other.user && this.additionalHeaders == other.additionalHeaders && this.additionalQueryParams == other.additionalQueryParams && this.additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ } override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(messages, model, frequencyPenalty, functionCall, functions, logitBias, logprobs, maxCompletionTokens, maxTokens, n, parallelToolCalls, presencePenalty, responseFormat, seed, serviceTier, stop, stream, streamOptions, temperature, toolChoice, tools, topLogprobs, topP, user, additionalQueryParams, additionalHeaders, additionalBodyProperties) /* spotless:on */ + return /* spotless:off */ Objects.hash(messages, model, frequencyPenalty, functionCall, functions, logitBias, logprobs, maxCompletionTokens, maxTokens, n, parallelToolCalls, presencePenalty, responseFormat, seed, serviceTier, stop, stream, streamOptions, temperature, toolChoice, tools, topLogprobs, topP, user, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */ } override fun toString() = - "ChatCompletionCreateParams{messages=$messages, model=$model, frequencyPenalty=$frequencyPenalty, functionCall=$functionCall, functions=$functions, logitBias=$logitBias, logprobs=$logprobs, maxCompletionTokens=$maxCompletionTokens, maxTokens=$maxTokens, n=$n, parallelToolCalls=$parallelToolCalls, presencePenalty=$presencePenalty, responseFormat=$responseFormat, seed=$seed, serviceTier=$serviceTier, stop=$stop, stream=$stream, streamOptions=$streamOptions, temperature=$temperature, toolChoice=$toolChoice, tools=$tools, topLogprobs=$topLogprobs, topP=$topP, user=$user, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + "ChatCompletionCreateParams{messages=$messages, model=$model, frequencyPenalty=$frequencyPenalty, functionCall=$functionCall, functions=$functions, logitBias=$logitBias, logprobs=$logprobs, maxCompletionTokens=$maxCompletionTokens, maxTokens=$maxTokens, n=$n, parallelToolCalls=$parallelToolCalls, presencePenalty=$presencePenalty, responseFormat=$responseFormat, seed=$seed, serviceTier=$serviceTier, stop=$stop, stream=$stream, streamOptions=$streamOptions, temperature=$temperature, toolChoice=$toolChoice, tools=$tools, topLogprobs=$topLogprobs, topP=$topP, user=$user, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" fun toBuilder() = Builder().from(this) @@ -813,8 +815,8 @@ constructor( private var topLogprobs: Long? = null private var topP: Double? = null private var user: 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() private var additionalBodyProperties: MutableMap = mutableMapOf() internal fun from(chatCompletionCreateParams: ChatCompletionCreateParams) = apply { @@ -842,8 +844,8 @@ constructor( this.topLogprobs = chatCompletionCreateParams.topLogprobs this.topP = chatCompletionCreateParams.topP this.user = chatCompletionCreateParams.user - additionalQueryParams(chatCompletionCreateParams.additionalQueryParams) additionalHeaders(chatCompletionCreateParams.additionalHeaders) + additionalQueryParams(chatCompletionCreateParams.additionalQueryParams) additionalBodyProperties(chatCompletionCreateParams.additionalBodyProperties) } @@ -874,16 +876,7 @@ constructor( * [model endpoint compatibility](/docs/models/model-endpoint-compatibility) table for * details on which models work with the Chat API. */ - fun model(string: String) = apply { this.model = Model.ofString(string) } - - /** - * ID of the model to use. See the - * [model endpoint compatibility](/docs/models/model-endpoint-compatibility) table for - * details on which models work with the Chat API. - */ - fun model(unionMember1: Model.UnionMember1) = apply { - this.model = Model.ofUnionMember1(unionMember1) - } + fun model(value: String) = apply { this.model = Model.of(value) } /** * Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing @@ -1153,7 +1146,7 @@ constructor( fun stop(string: String) = apply { this.stop = Stop.ofString(string) } /** Up to 4 sequences where the API will stop generating further tokens. */ - fun stop(strings: List) = apply { this.stop = Stop.ofStrings(strings) } + fun stopOfStrings(strings: List) = apply { this.stop = Stop.ofStrings(strings) } /** * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as @@ -1259,53 +1252,111 @@ constructor( */ fun user(user: String) = apply { this.user = user } - 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 putHeader(name: String, value: String) = apply { - this.additionalHeaders.getOrPut(name) { mutableListOf() }.add(value) + 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 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) = @@ -1313,14 +1364,21 @@ constructor( this.additionalBodyProperties.putAll(additionalBodyProperties) } + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + fun build(): ChatCompletionCreateParams = ChatCompletionCreateParams( - checkNotNull(messages) { "`messages` is required but was not set" } - .toUnmodifiable(), + checkNotNull(messages) { "`messages` is required but was not set" }.toImmutable(), checkNotNull(model) { "`model` is required but was not set" }, frequencyPenalty, functionCall, - if (functions.size == 0) null else functions.toUnmodifiable(), + if (functions.size == 0) null else functions.toImmutable(), logitBias, logprobs, maxCompletionTokens, @@ -1336,13 +1394,13 @@ constructor( streamOptions, temperature, toolChoice, - if (tools.size == 0) null else tools.toUnmodifiable(), + if (tools.size == 0) null else tools.toImmutable(), topLogprobs, topP, user, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } @@ -1537,6 +1595,7 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Message { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef()) { it.validate() } @@ -1718,7 +1777,7 @@ constructor( content, role, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -1726,8 +1785,8 @@ constructor( @JsonSerialize(using = Content.Serializer::class) class Content private constructor( - private val string: String? = null, - private val chatCompletionRequestMessageContentPartTexts: + private val textContent: String? = null, + private val arrayOfContentParts: List? = null, private val _json: JsonValue? = null, @@ -1736,49 +1795,40 @@ constructor( private var validated: Boolean = false /** The contents of the system message. */ - fun string(): String? = string + fun textContent(): String? = textContent /** * An array of content parts with a defined type. For system messages, only type * `text` is supported. */ - fun chatCompletionRequestMessageContentPartTexts(): - List? = - chatCompletionRequestMessageContentPartTexts + fun arrayOfContentParts(): List? = + arrayOfContentParts - fun isString(): Boolean = string != null + fun isTextContent(): Boolean = textContent != null - fun isChatCompletionRequestMessageContentPartTexts(): Boolean = - chatCompletionRequestMessageContentPartTexts != null + fun isArrayOfContentParts(): Boolean = arrayOfContentParts != null - fun asString(): String = string.getOrThrow("string") + fun asTextContent(): String = textContent.getOrThrow("textContent") - fun asChatCompletionRequestMessageContentPartTexts(): - List = - chatCompletionRequestMessageContentPartTexts.getOrThrow( - "chatCompletionRequestMessageContentPartTexts" - ) + fun asArrayOfContentParts(): List = + arrayOfContentParts.getOrThrow("arrayOfContentParts") fun _json(): JsonValue? = _json fun accept(visitor: Visitor): T { return when { - string != null -> visitor.visitString(string) - chatCompletionRequestMessageContentPartTexts != null -> - visitor.visitChatCompletionRequestMessageContentPartTexts( - chatCompletionRequestMessageContentPartTexts - ) + textContent != null -> visitor.visitTextContent(textContent) + arrayOfContentParts != null -> + visitor.visitArrayOfContentParts(arrayOfContentParts) else -> visitor.unknown(_json) } } fun validate(): Content = apply { if (!validated) { - if ( - string == null && chatCompletionRequestMessageContentPartTexts == null - ) { + if (textContent == null && arrayOfContentParts == null) { throw OmnistackInvalidDataException("Unknown Content: $_json") } - chatCompletionRequestMessageContentPartTexts?.forEach { it.validate() } + arrayOfContentParts?.forEach { it.validate() } validated = true } } @@ -1788,18 +1838,18 @@ constructor( return true } - return /* spotless:off */ other is Content && this.string == other.string && this.chatCompletionRequestMessageContentPartTexts == other.chatCompletionRequestMessageContentPartTexts /* spotless:on */ + return /* spotless:off */ other is Content && this.textContent == other.textContent && this.arrayOfContentParts == other.arrayOfContentParts /* spotless:on */ } override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(string, chatCompletionRequestMessageContentPartTexts) /* spotless:on */ + return /* spotless:off */ Objects.hash(textContent, arrayOfContentParts) /* spotless:on */ } override fun toString(): String { return when { - string != null -> "Content{string=$string}" - chatCompletionRequestMessageContentPartTexts != null -> - "Content{chatCompletionRequestMessageContentPartTexts=$chatCompletionRequestMessageContentPartTexts}" + textContent != null -> "Content{textContent=$textContent}" + arrayOfContentParts != null -> + "Content{arrayOfContentParts=$arrayOfContentParts}" _json != null -> "Content{_unknown=$_json}" else -> throw IllegalStateException("Invalid Content") } @@ -1807,25 +1857,19 @@ constructor( companion object { - fun ofString(string: String) = Content(string = string) + fun ofTextContent(textContent: String) = Content(textContent = textContent) - fun ofChatCompletionRequestMessageContentPartTexts( - chatCompletionRequestMessageContentPartTexts: - List - ) = - Content( - chatCompletionRequestMessageContentPartTexts = - chatCompletionRequestMessageContentPartTexts - ) + fun ofArrayOfContentParts( + arrayOfContentParts: List + ) = Content(arrayOfContentParts = arrayOfContentParts) } interface Visitor { - fun visitString(string: String): T + fun visitTextContent(textContent: String): T - fun visitChatCompletionRequestMessageContentPartTexts( - chatCompletionRequestMessageContentPartTexts: - List + fun visitArrayOfContentParts( + arrayOfContentParts: List ): T fun unknown(json: JsonValue?): T { @@ -1837,8 +1881,9 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Content { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { - return Content(string = it, _json = json) + return Content(textContent = it, _json = json) } tryDeserialize( node, @@ -1847,10 +1892,7 @@ constructor( it.forEach { it.validate() } } ?.let { - return Content( - chatCompletionRequestMessageContentPartTexts = it, - _json = json - ) + return Content(arrayOfContentParts = it, _json = json) } return Content(_json = json) @@ -1865,11 +1907,9 @@ constructor( provider: SerializerProvider ) { when { - value.string != null -> generator.writeObject(value.string) - value.chatCompletionRequestMessageContentPartTexts != null -> - generator.writeObject( - value.chatCompletionRequestMessageContentPartTexts - ) + value.textContent != null -> generator.writeObject(value.textContent) + value.arrayOfContentParts != null -> + generator.writeObject(value.arrayOfContentParts) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Content") } @@ -1973,7 +2013,7 @@ constructor( ChatCompletionRequestMessageContentPartText( type, text, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -2245,7 +2285,7 @@ constructor( content, role, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -2253,8 +2293,8 @@ constructor( @JsonSerialize(using = Content.Serializer::class) class Content private constructor( - private val string: String? = null, - private val chatCompletionRequestUserMessageContentParts: + private val textContent: String? = null, + private val arrayOfContentParts: List? = null, private val _json: JsonValue? = null, @@ -2263,48 +2303,39 @@ constructor( private var validated: Boolean = false /** The text contents of the message. */ - fun string(): String? = string + fun textContent(): String? = textContent /** * An array of content parts with a defined type, each can be of type `text` or * `image_url` when passing in images. You can pass multiple images by adding * multiple `image_url` content parts. Image input is only supported when using the * `gpt-4o` model. */ - fun chatCompletionRequestUserMessageContentParts(): - List? = - chatCompletionRequestUserMessageContentParts + fun arrayOfContentParts(): List? = + arrayOfContentParts - fun isString(): Boolean = string != null + fun isTextContent(): Boolean = textContent != null - fun isChatCompletionRequestUserMessageContentParts(): Boolean = - chatCompletionRequestUserMessageContentParts != null + fun isArrayOfContentParts(): Boolean = arrayOfContentParts != null - fun asString(): String = string.getOrThrow("string") + fun asTextContent(): String = textContent.getOrThrow("textContent") - fun asChatCompletionRequestUserMessageContentParts(): - List = - chatCompletionRequestUserMessageContentParts.getOrThrow( - "chatCompletionRequestUserMessageContentParts" - ) + fun asArrayOfContentParts(): List = + arrayOfContentParts.getOrThrow("arrayOfContentParts") fun _json(): JsonValue? = _json fun accept(visitor: Visitor): T { return when { - string != null -> visitor.visitString(string) - chatCompletionRequestUserMessageContentParts != null -> - visitor.visitChatCompletionRequestUserMessageContentParts( - chatCompletionRequestUserMessageContentParts - ) + textContent != null -> visitor.visitTextContent(textContent) + arrayOfContentParts != null -> + visitor.visitArrayOfContentParts(arrayOfContentParts) else -> visitor.unknown(_json) } } fun validate(): Content = apply { if (!validated) { - if ( - string == null && chatCompletionRequestUserMessageContentParts == null - ) { + if (textContent == null && arrayOfContentParts == null) { throw OmnistackInvalidDataException("Unknown Content: $_json") } validated = true @@ -2316,18 +2347,18 @@ constructor( return true } - return /* spotless:off */ other is Content && this.string == other.string && this.chatCompletionRequestUserMessageContentParts == other.chatCompletionRequestUserMessageContentParts /* spotless:on */ + return /* spotless:off */ other is Content && this.textContent == other.textContent && this.arrayOfContentParts == other.arrayOfContentParts /* spotless:on */ } override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(string, chatCompletionRequestUserMessageContentParts) /* spotless:on */ + return /* spotless:off */ Objects.hash(textContent, arrayOfContentParts) /* spotless:on */ } override fun toString(): String { return when { - string != null -> "Content{string=$string}" - chatCompletionRequestUserMessageContentParts != null -> - "Content{chatCompletionRequestUserMessageContentParts=$chatCompletionRequestUserMessageContentParts}" + textContent != null -> "Content{textContent=$textContent}" + arrayOfContentParts != null -> + "Content{arrayOfContentParts=$arrayOfContentParts}" _json != null -> "Content{_unknown=$_json}" else -> throw IllegalStateException("Invalid Content") } @@ -2335,25 +2366,19 @@ constructor( companion object { - fun ofString(string: String) = Content(string = string) + fun ofTextContent(textContent: String) = Content(textContent = textContent) - fun ofChatCompletionRequestUserMessageContentParts( - chatCompletionRequestUserMessageContentParts: - List - ) = - Content( - chatCompletionRequestUserMessageContentParts = - chatCompletionRequestUserMessageContentParts - ) + fun ofArrayOfContentParts( + arrayOfContentParts: List + ) = Content(arrayOfContentParts = arrayOfContentParts) } interface Visitor { - fun visitString(string: String): T + fun visitTextContent(textContent: String): T - fun visitChatCompletionRequestUserMessageContentParts( - chatCompletionRequestUserMessageContentParts: - List + fun visitArrayOfContentParts( + arrayOfContentParts: List ): T fun unknown(json: JsonValue?): T { @@ -2365,18 +2390,16 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Content { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { - return Content(string = it, _json = json) + return Content(textContent = it, _json = json) } tryDeserialize( node, jacksonTypeRef>() ) ?.let { - return Content( - chatCompletionRequestUserMessageContentParts = it, - _json = json - ) + return Content(arrayOfContentParts = it, _json = json) } return Content(_json = json) @@ -2391,11 +2414,9 @@ constructor( provider: SerializerProvider ) { when { - value.string != null -> generator.writeObject(value.string) - value.chatCompletionRequestUserMessageContentParts != null -> - generator.writeObject( - value.chatCompletionRequestUserMessageContentParts - ) + value.textContent != null -> generator.writeObject(value.textContent) + value.arrayOfContentParts != null -> + generator.writeObject(value.arrayOfContentParts) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Content") } @@ -2555,6 +2576,7 @@ constructor( node: JsonNode ): ChatCompletionRequestUserMessageContentPart { val json = JsonValue.fromJsonNode(node) + tryDeserialize( node, jacksonTypeRef() @@ -2709,7 +2731,7 @@ constructor( ChatCompletionRequestMessageContentPartText( type, text, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -2884,7 +2906,7 @@ constructor( ChatCompletionRequestMessageContentPartImage( type, imageUrl, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -2994,7 +3016,7 @@ constructor( ImageUrl( url, detail, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -3440,9 +3462,9 @@ constructor( refusal, role, name, - toolCalls.map { it.toUnmodifiable() }, + toolCalls.map { it.toImmutable() }, functionCall, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -3501,8 +3523,8 @@ constructor( @JsonSerialize(using = Content.Serializer::class) class Content private constructor( - private val string: String? = null, - private val chatCompletionRequestAssistantMessageContentParts: + private val textContent: String? = null, + private val arrayOfContentParts: List? = null, private val _json: JsonValue? = null, @@ -3511,47 +3533,38 @@ constructor( private var validated: Boolean = false /** The contents of the assistant message. */ - fun string(): String? = string + fun textContent(): String? = textContent /** * An array of content parts with a defined type. Can be one or more of type `text`, * or exactly one of type `refusal`. */ - fun chatCompletionRequestAssistantMessageContentParts(): - List? = - chatCompletionRequestAssistantMessageContentParts + fun arrayOfContentParts(): List? = + arrayOfContentParts - fun isString(): Boolean = string != null + fun isTextContent(): Boolean = textContent != null - fun isChatCompletionRequestAssistantMessageContentParts(): Boolean = - chatCompletionRequestAssistantMessageContentParts != null + fun isArrayOfContentParts(): Boolean = arrayOfContentParts != null - fun asString(): String = string.getOrThrow("string") + fun asTextContent(): String = textContent.getOrThrow("textContent") - fun asChatCompletionRequestAssistantMessageContentParts(): + fun asArrayOfContentParts(): List = - chatCompletionRequestAssistantMessageContentParts.getOrThrow( - "chatCompletionRequestAssistantMessageContentParts" - ) + arrayOfContentParts.getOrThrow("arrayOfContentParts") fun _json(): JsonValue? = _json fun accept(visitor: Visitor): T { return when { - string != null -> visitor.visitString(string) - chatCompletionRequestAssistantMessageContentParts != null -> - visitor.visitChatCompletionRequestAssistantMessageContentParts( - chatCompletionRequestAssistantMessageContentParts - ) + textContent != null -> visitor.visitTextContent(textContent) + arrayOfContentParts != null -> + visitor.visitArrayOfContentParts(arrayOfContentParts) else -> visitor.unknown(_json) } } fun validate(): Content = apply { if (!validated) { - if ( - string == null && - chatCompletionRequestAssistantMessageContentParts == null - ) { + if (textContent == null && arrayOfContentParts == null) { throw OmnistackInvalidDataException("Unknown Content: $_json") } validated = true @@ -3563,18 +3576,18 @@ constructor( return true } - return /* spotless:off */ other is Content && this.string == other.string && this.chatCompletionRequestAssistantMessageContentParts == other.chatCompletionRequestAssistantMessageContentParts /* spotless:on */ + return /* spotless:off */ other is Content && this.textContent == other.textContent && this.arrayOfContentParts == other.arrayOfContentParts /* spotless:on */ } override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(string, chatCompletionRequestAssistantMessageContentParts) /* spotless:on */ + return /* spotless:off */ Objects.hash(textContent, arrayOfContentParts) /* spotless:on */ } override fun toString(): String { return when { - string != null -> "Content{string=$string}" - chatCompletionRequestAssistantMessageContentParts != null -> - "Content{chatCompletionRequestAssistantMessageContentParts=$chatCompletionRequestAssistantMessageContentParts}" + textContent != null -> "Content{textContent=$textContent}" + arrayOfContentParts != null -> + "Content{arrayOfContentParts=$arrayOfContentParts}" _json != null -> "Content{_unknown=$_json}" else -> throw IllegalStateException("Invalid Content") } @@ -3582,25 +3595,19 @@ constructor( companion object { - fun ofString(string: String) = Content(string = string) + fun ofTextContent(textContent: String) = Content(textContent = textContent) - fun ofChatCompletionRequestAssistantMessageContentParts( - chatCompletionRequestAssistantMessageContentParts: - List - ) = - Content( - chatCompletionRequestAssistantMessageContentParts = - chatCompletionRequestAssistantMessageContentParts - ) + fun ofArrayOfContentParts( + arrayOfContentParts: List + ) = Content(arrayOfContentParts = arrayOfContentParts) } interface Visitor { - fun visitString(string: String): T + fun visitTextContent(textContent: String): T - fun visitChatCompletionRequestAssistantMessageContentParts( - chatCompletionRequestAssistantMessageContentParts: - List + fun visitArrayOfContentParts( + arrayOfContentParts: List ): T fun unknown(json: JsonValue?): T { @@ -3612,8 +3619,9 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Content { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { - return Content(string = it, _json = json) + return Content(textContent = it, _json = json) } tryDeserialize( node, @@ -3622,10 +3630,7 @@ constructor( >() ) ?.let { - return Content( - chatCompletionRequestAssistantMessageContentParts = it, - _json = json - ) + return Content(arrayOfContentParts = it, _json = json) } return Content(_json = json) @@ -3640,11 +3645,9 @@ constructor( provider: SerializerProvider ) { when { - value.string != null -> generator.writeObject(value.string) - value.chatCompletionRequestAssistantMessageContentParts != null -> - generator.writeObject( - value.chatCompletionRequestAssistantMessageContentParts - ) + value.textContent != null -> generator.writeObject(value.textContent) + value.arrayOfContentParts != null -> + generator.writeObject(value.arrayOfContentParts) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Content") } @@ -3804,6 +3807,7 @@ constructor( node: JsonNode ): ChatCompletionRequestAssistantMessageContentPart { val json = JsonValue.fromJsonNode(node) + tryDeserialize( node, jacksonTypeRef() @@ -3958,7 +3962,7 @@ constructor( ChatCompletionRequestMessageContentPartText( type, text, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -4137,7 +4141,7 @@ constructor( ChatCompletionRequestMessageContentPartRefusal( type, refusal, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -4332,7 +4336,7 @@ constructor( FunctionCall( arguments, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -4465,7 +4469,7 @@ constructor( id, type, function, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -4582,7 +4586,7 @@ constructor( Function( name, arguments, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -4813,7 +4817,7 @@ constructor( role, content, toolCallId, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -4821,8 +4825,8 @@ constructor( @JsonSerialize(using = Content.Serializer::class) class Content private constructor( - private val string: String? = null, - private val chatCompletionRequestMessageContentPartTexts: + private val textContent: String? = null, + private val arrayOfContentParts: List? = null, private val _json: JsonValue? = null, @@ -4831,49 +4835,40 @@ constructor( private var validated: Boolean = false /** The contents of the tool message. */ - fun string(): String? = string + fun textContent(): String? = textContent /** * An array of content parts with a defined type. For tool messages, only type * `text` is supported. */ - fun chatCompletionRequestMessageContentPartTexts(): - List? = - chatCompletionRequestMessageContentPartTexts + fun arrayOfContentParts(): List? = + arrayOfContentParts - fun isString(): Boolean = string != null + fun isTextContent(): Boolean = textContent != null - fun isChatCompletionRequestMessageContentPartTexts(): Boolean = - chatCompletionRequestMessageContentPartTexts != null + fun isArrayOfContentParts(): Boolean = arrayOfContentParts != null - fun asString(): String = string.getOrThrow("string") + fun asTextContent(): String = textContent.getOrThrow("textContent") - fun asChatCompletionRequestMessageContentPartTexts(): - List = - chatCompletionRequestMessageContentPartTexts.getOrThrow( - "chatCompletionRequestMessageContentPartTexts" - ) + fun asArrayOfContentParts(): List = + arrayOfContentParts.getOrThrow("arrayOfContentParts") fun _json(): JsonValue? = _json fun accept(visitor: Visitor): T { return when { - string != null -> visitor.visitString(string) - chatCompletionRequestMessageContentPartTexts != null -> - visitor.visitChatCompletionRequestMessageContentPartTexts( - chatCompletionRequestMessageContentPartTexts - ) + textContent != null -> visitor.visitTextContent(textContent) + arrayOfContentParts != null -> + visitor.visitArrayOfContentParts(arrayOfContentParts) else -> visitor.unknown(_json) } } fun validate(): Content = apply { if (!validated) { - if ( - string == null && chatCompletionRequestMessageContentPartTexts == null - ) { + if (textContent == null && arrayOfContentParts == null) { throw OmnistackInvalidDataException("Unknown Content: $_json") } - chatCompletionRequestMessageContentPartTexts?.forEach { it.validate() } + arrayOfContentParts?.forEach { it.validate() } validated = true } } @@ -4883,18 +4878,18 @@ constructor( return true } - return /* spotless:off */ other is Content && this.string == other.string && this.chatCompletionRequestMessageContentPartTexts == other.chatCompletionRequestMessageContentPartTexts /* spotless:on */ + return /* spotless:off */ other is Content && this.textContent == other.textContent && this.arrayOfContentParts == other.arrayOfContentParts /* spotless:on */ } override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(string, chatCompletionRequestMessageContentPartTexts) /* spotless:on */ + return /* spotless:off */ Objects.hash(textContent, arrayOfContentParts) /* spotless:on */ } override fun toString(): String { return when { - string != null -> "Content{string=$string}" - chatCompletionRequestMessageContentPartTexts != null -> - "Content{chatCompletionRequestMessageContentPartTexts=$chatCompletionRequestMessageContentPartTexts}" + textContent != null -> "Content{textContent=$textContent}" + arrayOfContentParts != null -> + "Content{arrayOfContentParts=$arrayOfContentParts}" _json != null -> "Content{_unknown=$_json}" else -> throw IllegalStateException("Invalid Content") } @@ -4902,25 +4897,19 @@ constructor( companion object { - fun ofString(string: String) = Content(string = string) + fun ofTextContent(textContent: String) = Content(textContent = textContent) - fun ofChatCompletionRequestMessageContentPartTexts( - chatCompletionRequestMessageContentPartTexts: - List - ) = - Content( - chatCompletionRequestMessageContentPartTexts = - chatCompletionRequestMessageContentPartTexts - ) + fun ofArrayOfContentParts( + arrayOfContentParts: List + ) = Content(arrayOfContentParts = arrayOfContentParts) } interface Visitor { - fun visitString(string: String): T + fun visitTextContent(textContent: String): T - fun visitChatCompletionRequestMessageContentPartTexts( - chatCompletionRequestMessageContentPartTexts: - List + fun visitArrayOfContentParts( + arrayOfContentParts: List ): T fun unknown(json: JsonValue?): T { @@ -4932,8 +4921,9 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Content { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { - return Content(string = it, _json = json) + return Content(textContent = it, _json = json) } tryDeserialize( node, @@ -4942,10 +4932,7 @@ constructor( it.forEach { it.validate() } } ?.let { - return Content( - chatCompletionRequestMessageContentPartTexts = it, - _json = json - ) + return Content(arrayOfContentParts = it, _json = json) } return Content(_json = json) @@ -4960,11 +4947,9 @@ constructor( provider: SerializerProvider ) { when { - value.string != null -> generator.writeObject(value.string) - value.chatCompletionRequestMessageContentPartTexts != null -> - generator.writeObject( - value.chatCompletionRequestMessageContentPartTexts - ) + value.textContent != null -> generator.writeObject(value.textContent) + value.arrayOfContentParts != null -> + generator.writeObject(value.arrayOfContentParts) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Content") } @@ -5068,7 +5053,7 @@ constructor( ChatCompletionRequestMessageContentPartText( type, text, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -5328,7 +5313,7 @@ constructor( role, content, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -5405,336 +5390,223 @@ constructor( } } - @JsonDeserialize(using = Model.Deserializer::class) - @JsonSerialize(using = Model.Serializer::class) class Model + @JsonCreator private constructor( - private val string: String? = null, - private val unionMember1: UnionMember1? = null, - private val _json: JsonValue? = null, - ) { - - private var validated: Boolean = false - - fun string(): String? = string - - fun unionMember1(): UnionMember1? = unionMember1 - - fun isString(): Boolean = string != null - - fun isUnionMember1(): Boolean = unionMember1 != null - - fun asString(): String = string.getOrThrow("string") - - fun asUnionMember1(): UnionMember1 = unionMember1.getOrThrow("unionMember1") - - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { - string != null -> visitor.visitString(string) - unionMember1 != null -> visitor.visitUnionMember1(unionMember1) - else -> visitor.unknown(_json) - } - } + private val value: JsonField, + ) : Enum { - fun validate(): Model = apply { - if (!validated) { - if (string == null && unionMember1 == null) { - throw OmnistackInvalidDataException("Unknown Model: $_json") - } - validated = true - } - } + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Model && this.string == other.string && this.unionMember1 == other.unionMember1 /* spotless:on */ + return /* spotless:off */ other is Model && this.value == other.value /* spotless:on */ } - override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(string, unionMember1) /* spotless:on */ - } + override fun hashCode() = value.hashCode() - override fun toString(): String { - return when { - string != null -> "Model{string=$string}" - unionMember1 != null -> "Model{unionMember1=$unionMember1}" - _json != null -> "Model{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Model") - } - } + override fun toString() = value.toString() companion object { - fun ofString(string: String) = Model(string = string) + val O1_PREVIEW = Model(JsonField.of("o1-preview")) - fun ofUnionMember1(unionMember1: UnionMember1) = Model(unionMember1 = unionMember1) - } + val O1_PREVIEW_2024_09_12 = Model(JsonField.of("o1-preview-2024-09-12")) - interface Visitor { + val O1_MINI = Model(JsonField.of("o1-mini")) - fun visitString(string: String): T + val O1_MINI_2024_09_12 = Model(JsonField.of("o1-mini-2024-09-12")) - fun visitUnionMember1(unionMember1: UnionMember1): T + val GPT_4O = Model(JsonField.of("gpt-4o")) - fun unknown(json: JsonValue?): T { - throw OmnistackInvalidDataException("Unknown Model: $json") - } - } + val GPT_4O_2024_08_06 = Model(JsonField.of("gpt-4o-2024-08-06")) - class Deserializer : BaseDeserializer(Model::class) { + val GPT_4O_2024_05_13 = Model(JsonField.of("gpt-4o-2024-05-13")) - override fun ObjectCodec.deserialize(node: JsonNode): Model { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Model(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef())?.let { - return Model(unionMember1 = it, _json = json) - } + val CHATGPT_4O_LATEST = Model(JsonField.of("chatgpt-4o-latest")) - return Model(_json = json) - } - } + val GPT_4O_MINI = Model(JsonField.of("gpt-4o-mini")) - class Serializer : BaseSerializer(Model::class) { + val GPT_4O_MINI_2024_07_18 = Model(JsonField.of("gpt-4o-mini-2024-07-18")) - override fun serialize( - value: Model, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.unionMember1 != null -> generator.writeObject(value.unionMember1) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Model") - } - } - } + val GPT_4_TURBO = Model(JsonField.of("gpt-4-turbo")) - class UnionMember1 - @JsonCreator - private constructor( - private val value: JsonField, - ) : Enum { + val GPT_4_TURBO_2024_04_09 = Model(JsonField.of("gpt-4-turbo-2024-04-09")) - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + val GPT_4_0125_PREVIEW = Model(JsonField.of("gpt-4-0125-preview")) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + val GPT_4_TURBO_PREVIEW = Model(JsonField.of("gpt-4-turbo-preview")) - return /* spotless:off */ other is UnionMember1 && this.value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val O1_PREVIEW = UnionMember1(JsonField.of("o1-preview")) - - val O1_PREVIEW_2024_09_12 = UnionMember1(JsonField.of("o1-preview-2024-09-12")) - - val O1_MINI = UnionMember1(JsonField.of("o1-mini")) - - val O1_MINI_2024_09_12 = UnionMember1(JsonField.of("o1-mini-2024-09-12")) - - val GPT_4O = UnionMember1(JsonField.of("gpt-4o")) - - val GPT_4O_2024_08_06 = UnionMember1(JsonField.of("gpt-4o-2024-08-06")) + val GPT_4_1106_PREVIEW = Model(JsonField.of("gpt-4-1106-preview")) - val GPT_4O_2024_05_13 = UnionMember1(JsonField.of("gpt-4o-2024-05-13")) + val GPT_4_VISION_PREVIEW = Model(JsonField.of("gpt-4-vision-preview")) - val CHATGPT_4O_LATEST = UnionMember1(JsonField.of("chatgpt-4o-latest")) + val GPT_4 = Model(JsonField.of("gpt-4")) - val GPT_4O_MINI = UnionMember1(JsonField.of("gpt-4o-mini")) + val GPT_4_0314 = Model(JsonField.of("gpt-4-0314")) - val GPT_4O_MINI_2024_07_18 = UnionMember1(JsonField.of("gpt-4o-mini-2024-07-18")) + val GPT_4_0613 = Model(JsonField.of("gpt-4-0613")) - val GPT_4_TURBO = UnionMember1(JsonField.of("gpt-4-turbo")) + val GPT_4_32K = Model(JsonField.of("gpt-4-32k")) - val GPT_4_TURBO_2024_04_09 = UnionMember1(JsonField.of("gpt-4-turbo-2024-04-09")) + val GPT_4_32K_0314 = Model(JsonField.of("gpt-4-32k-0314")) - val GPT_4_0125_PREVIEW = UnionMember1(JsonField.of("gpt-4-0125-preview")) + val GPT_4_32K_0613 = Model(JsonField.of("gpt-4-32k-0613")) - val GPT_4_TURBO_PREVIEW = UnionMember1(JsonField.of("gpt-4-turbo-preview")) + val GPT_3_5_TURBO = Model(JsonField.of("gpt-3.5-turbo")) - val GPT_4_1106_PREVIEW = UnionMember1(JsonField.of("gpt-4-1106-preview")) + val GPT_3_5_TURBO_16K = Model(JsonField.of("gpt-3.5-turbo-16k")) - val GPT_4_VISION_PREVIEW = UnionMember1(JsonField.of("gpt-4-vision-preview")) + val GPT_3_5_TURBO_0301 = Model(JsonField.of("gpt-3.5-turbo-0301")) - val GPT_4 = UnionMember1(JsonField.of("gpt-4")) + val GPT_3_5_TURBO_0613 = Model(JsonField.of("gpt-3.5-turbo-0613")) - val GPT_4_0314 = UnionMember1(JsonField.of("gpt-4-0314")) + val GPT_3_5_TURBO_1106 = Model(JsonField.of("gpt-3.5-turbo-1106")) - val GPT_4_0613 = UnionMember1(JsonField.of("gpt-4-0613")) + val GPT_3_5_TURBO_0125 = Model(JsonField.of("gpt-3.5-turbo-0125")) - val GPT_4_32K = UnionMember1(JsonField.of("gpt-4-32k")) + val GPT_3_5_TURBO_16K_0613 = Model(JsonField.of("gpt-3.5-turbo-16k-0613")) - val GPT_4_32K_0314 = UnionMember1(JsonField.of("gpt-4-32k-0314")) - - val GPT_4_32K_0613 = UnionMember1(JsonField.of("gpt-4-32k-0613")) - - val GPT_3_5_TURBO = UnionMember1(JsonField.of("gpt-3.5-turbo")) - - val GPT_3_5_TURBO_16K = UnionMember1(JsonField.of("gpt-3.5-turbo-16k")) - - val GPT_3_5_TURBO_0301 = UnionMember1(JsonField.of("gpt-3.5-turbo-0301")) - - val GPT_3_5_TURBO_0613 = UnionMember1(JsonField.of("gpt-3.5-turbo-0613")) - - val GPT_3_5_TURBO_1106 = UnionMember1(JsonField.of("gpt-3.5-turbo-1106")) - - val GPT_3_5_TURBO_0125 = UnionMember1(JsonField.of("gpt-3.5-turbo-0125")) + fun of(value: String) = Model(JsonField.of(value)) + } - val GPT_3_5_TURBO_16K_0613 = UnionMember1(JsonField.of("gpt-3.5-turbo-16k-0613")) + enum class Known { + O1_PREVIEW, + O1_PREVIEW_2024_09_12, + O1_MINI, + O1_MINI_2024_09_12, + GPT_4O, + GPT_4O_2024_08_06, + GPT_4O_2024_05_13, + CHATGPT_4O_LATEST, + GPT_4O_MINI, + GPT_4O_MINI_2024_07_18, + GPT_4_TURBO, + GPT_4_TURBO_2024_04_09, + GPT_4_0125_PREVIEW, + GPT_4_TURBO_PREVIEW, + GPT_4_1106_PREVIEW, + GPT_4_VISION_PREVIEW, + GPT_4, + GPT_4_0314, + GPT_4_0613, + GPT_4_32K, + GPT_4_32K_0314, + GPT_4_32K_0613, + GPT_3_5_TURBO, + GPT_3_5_TURBO_16K, + GPT_3_5_TURBO_0301, + GPT_3_5_TURBO_0613, + GPT_3_5_TURBO_1106, + GPT_3_5_TURBO_0125, + GPT_3_5_TURBO_16K_0613, + } - fun of(value: String) = UnionMember1(JsonField.of(value)) - } + enum class Value { + O1_PREVIEW, + O1_PREVIEW_2024_09_12, + O1_MINI, + O1_MINI_2024_09_12, + GPT_4O, + GPT_4O_2024_08_06, + GPT_4O_2024_05_13, + CHATGPT_4O_LATEST, + GPT_4O_MINI, + GPT_4O_MINI_2024_07_18, + GPT_4_TURBO, + GPT_4_TURBO_2024_04_09, + GPT_4_0125_PREVIEW, + GPT_4_TURBO_PREVIEW, + GPT_4_1106_PREVIEW, + GPT_4_VISION_PREVIEW, + GPT_4, + GPT_4_0314, + GPT_4_0613, + GPT_4_32K, + GPT_4_32K_0314, + GPT_4_32K_0613, + GPT_3_5_TURBO, + GPT_3_5_TURBO_16K, + GPT_3_5_TURBO_0301, + GPT_3_5_TURBO_0613, + GPT_3_5_TURBO_1106, + GPT_3_5_TURBO_0125, + GPT_3_5_TURBO_16K_0613, + _UNKNOWN, + } - enum class Known { - O1_PREVIEW, - O1_PREVIEW_2024_09_12, - O1_MINI, - O1_MINI_2024_09_12, - GPT_4O, - GPT_4O_2024_08_06, - GPT_4O_2024_05_13, - CHATGPT_4O_LATEST, - GPT_4O_MINI, - GPT_4O_MINI_2024_07_18, - GPT_4_TURBO, - GPT_4_TURBO_2024_04_09, - GPT_4_0125_PREVIEW, - GPT_4_TURBO_PREVIEW, - GPT_4_1106_PREVIEW, - GPT_4_VISION_PREVIEW, - GPT_4, - GPT_4_0314, - GPT_4_0613, - GPT_4_32K, - GPT_4_32K_0314, - GPT_4_32K_0613, - GPT_3_5_TURBO, - GPT_3_5_TURBO_16K, - GPT_3_5_TURBO_0301, - GPT_3_5_TURBO_0613, - GPT_3_5_TURBO_1106, - GPT_3_5_TURBO_0125, - GPT_3_5_TURBO_16K_0613, + fun value(): Value = + when (this) { + O1_PREVIEW -> Value.O1_PREVIEW + O1_PREVIEW_2024_09_12 -> Value.O1_PREVIEW_2024_09_12 + O1_MINI -> Value.O1_MINI + O1_MINI_2024_09_12 -> Value.O1_MINI_2024_09_12 + GPT_4O -> Value.GPT_4O + GPT_4O_2024_08_06 -> Value.GPT_4O_2024_08_06 + GPT_4O_2024_05_13 -> Value.GPT_4O_2024_05_13 + CHATGPT_4O_LATEST -> Value.CHATGPT_4O_LATEST + GPT_4O_MINI -> Value.GPT_4O_MINI + GPT_4O_MINI_2024_07_18 -> Value.GPT_4O_MINI_2024_07_18 + GPT_4_TURBO -> Value.GPT_4_TURBO + GPT_4_TURBO_2024_04_09 -> Value.GPT_4_TURBO_2024_04_09 + GPT_4_0125_PREVIEW -> Value.GPT_4_0125_PREVIEW + GPT_4_TURBO_PREVIEW -> Value.GPT_4_TURBO_PREVIEW + GPT_4_1106_PREVIEW -> Value.GPT_4_1106_PREVIEW + GPT_4_VISION_PREVIEW -> Value.GPT_4_VISION_PREVIEW + GPT_4 -> Value.GPT_4 + GPT_4_0314 -> Value.GPT_4_0314 + GPT_4_0613 -> Value.GPT_4_0613 + GPT_4_32K -> Value.GPT_4_32K + GPT_4_32K_0314 -> Value.GPT_4_32K_0314 + GPT_4_32K_0613 -> Value.GPT_4_32K_0613 + GPT_3_5_TURBO -> Value.GPT_3_5_TURBO + GPT_3_5_TURBO_16K -> Value.GPT_3_5_TURBO_16K + GPT_3_5_TURBO_0301 -> Value.GPT_3_5_TURBO_0301 + GPT_3_5_TURBO_0613 -> Value.GPT_3_5_TURBO_0613 + GPT_3_5_TURBO_1106 -> Value.GPT_3_5_TURBO_1106 + GPT_3_5_TURBO_0125 -> Value.GPT_3_5_TURBO_0125 + GPT_3_5_TURBO_16K_0613 -> Value.GPT_3_5_TURBO_16K_0613 + else -> Value._UNKNOWN } - enum class Value { - O1_PREVIEW, - O1_PREVIEW_2024_09_12, - O1_MINI, - O1_MINI_2024_09_12, - GPT_4O, - GPT_4O_2024_08_06, - GPT_4O_2024_05_13, - CHATGPT_4O_LATEST, - GPT_4O_MINI, - GPT_4O_MINI_2024_07_18, - GPT_4_TURBO, - GPT_4_TURBO_2024_04_09, - GPT_4_0125_PREVIEW, - GPT_4_TURBO_PREVIEW, - GPT_4_1106_PREVIEW, - GPT_4_VISION_PREVIEW, - GPT_4, - GPT_4_0314, - GPT_4_0613, - GPT_4_32K, - GPT_4_32K_0314, - GPT_4_32K_0613, - GPT_3_5_TURBO, - GPT_3_5_TURBO_16K, - GPT_3_5_TURBO_0301, - GPT_3_5_TURBO_0613, - GPT_3_5_TURBO_1106, - GPT_3_5_TURBO_0125, - GPT_3_5_TURBO_16K_0613, - _UNKNOWN, + fun known(): Known = + when (this) { + O1_PREVIEW -> Known.O1_PREVIEW + O1_PREVIEW_2024_09_12 -> Known.O1_PREVIEW_2024_09_12 + O1_MINI -> Known.O1_MINI + O1_MINI_2024_09_12 -> Known.O1_MINI_2024_09_12 + GPT_4O -> Known.GPT_4O + GPT_4O_2024_08_06 -> Known.GPT_4O_2024_08_06 + GPT_4O_2024_05_13 -> Known.GPT_4O_2024_05_13 + CHATGPT_4O_LATEST -> Known.CHATGPT_4O_LATEST + GPT_4O_MINI -> Known.GPT_4O_MINI + GPT_4O_MINI_2024_07_18 -> Known.GPT_4O_MINI_2024_07_18 + GPT_4_TURBO -> Known.GPT_4_TURBO + GPT_4_TURBO_2024_04_09 -> Known.GPT_4_TURBO_2024_04_09 + GPT_4_0125_PREVIEW -> Known.GPT_4_0125_PREVIEW + GPT_4_TURBO_PREVIEW -> Known.GPT_4_TURBO_PREVIEW + GPT_4_1106_PREVIEW -> Known.GPT_4_1106_PREVIEW + GPT_4_VISION_PREVIEW -> Known.GPT_4_VISION_PREVIEW + GPT_4 -> Known.GPT_4 + GPT_4_0314 -> Known.GPT_4_0314 + GPT_4_0613 -> Known.GPT_4_0613 + GPT_4_32K -> Known.GPT_4_32K + GPT_4_32K_0314 -> Known.GPT_4_32K_0314 + GPT_4_32K_0613 -> Known.GPT_4_32K_0613 + GPT_3_5_TURBO -> Known.GPT_3_5_TURBO + GPT_3_5_TURBO_16K -> Known.GPT_3_5_TURBO_16K + GPT_3_5_TURBO_0301 -> Known.GPT_3_5_TURBO_0301 + GPT_3_5_TURBO_0613 -> Known.GPT_3_5_TURBO_0613 + GPT_3_5_TURBO_1106 -> Known.GPT_3_5_TURBO_1106 + GPT_3_5_TURBO_0125 -> Known.GPT_3_5_TURBO_0125 + GPT_3_5_TURBO_16K_0613 -> Known.GPT_3_5_TURBO_16K_0613 + else -> throw OmnistackInvalidDataException("Unknown Model: $value") } - fun value(): Value = - when (this) { - O1_PREVIEW -> Value.O1_PREVIEW - O1_PREVIEW_2024_09_12 -> Value.O1_PREVIEW_2024_09_12 - O1_MINI -> Value.O1_MINI - O1_MINI_2024_09_12 -> Value.O1_MINI_2024_09_12 - GPT_4O -> Value.GPT_4O - GPT_4O_2024_08_06 -> Value.GPT_4O_2024_08_06 - GPT_4O_2024_05_13 -> Value.GPT_4O_2024_05_13 - CHATGPT_4O_LATEST -> Value.CHATGPT_4O_LATEST - GPT_4O_MINI -> Value.GPT_4O_MINI - GPT_4O_MINI_2024_07_18 -> Value.GPT_4O_MINI_2024_07_18 - GPT_4_TURBO -> Value.GPT_4_TURBO - GPT_4_TURBO_2024_04_09 -> Value.GPT_4_TURBO_2024_04_09 - GPT_4_0125_PREVIEW -> Value.GPT_4_0125_PREVIEW - GPT_4_TURBO_PREVIEW -> Value.GPT_4_TURBO_PREVIEW - GPT_4_1106_PREVIEW -> Value.GPT_4_1106_PREVIEW - GPT_4_VISION_PREVIEW -> Value.GPT_4_VISION_PREVIEW - GPT_4 -> Value.GPT_4 - GPT_4_0314 -> Value.GPT_4_0314 - GPT_4_0613 -> Value.GPT_4_0613 - GPT_4_32K -> Value.GPT_4_32K - GPT_4_32K_0314 -> Value.GPT_4_32K_0314 - GPT_4_32K_0613 -> Value.GPT_4_32K_0613 - GPT_3_5_TURBO -> Value.GPT_3_5_TURBO - GPT_3_5_TURBO_16K -> Value.GPT_3_5_TURBO_16K - GPT_3_5_TURBO_0301 -> Value.GPT_3_5_TURBO_0301 - GPT_3_5_TURBO_0613 -> Value.GPT_3_5_TURBO_0613 - GPT_3_5_TURBO_1106 -> Value.GPT_3_5_TURBO_1106 - GPT_3_5_TURBO_0125 -> Value.GPT_3_5_TURBO_0125 - GPT_3_5_TURBO_16K_0613 -> Value.GPT_3_5_TURBO_16K_0613 - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - O1_PREVIEW -> Known.O1_PREVIEW - O1_PREVIEW_2024_09_12 -> Known.O1_PREVIEW_2024_09_12 - O1_MINI -> Known.O1_MINI - O1_MINI_2024_09_12 -> Known.O1_MINI_2024_09_12 - GPT_4O -> Known.GPT_4O - GPT_4O_2024_08_06 -> Known.GPT_4O_2024_08_06 - GPT_4O_2024_05_13 -> Known.GPT_4O_2024_05_13 - CHATGPT_4O_LATEST -> Known.CHATGPT_4O_LATEST - GPT_4O_MINI -> Known.GPT_4O_MINI - GPT_4O_MINI_2024_07_18 -> Known.GPT_4O_MINI_2024_07_18 - GPT_4_TURBO -> Known.GPT_4_TURBO - GPT_4_TURBO_2024_04_09 -> Known.GPT_4_TURBO_2024_04_09 - GPT_4_0125_PREVIEW -> Known.GPT_4_0125_PREVIEW - GPT_4_TURBO_PREVIEW -> Known.GPT_4_TURBO_PREVIEW - GPT_4_1106_PREVIEW -> Known.GPT_4_1106_PREVIEW - GPT_4_VISION_PREVIEW -> Known.GPT_4_VISION_PREVIEW - GPT_4 -> Known.GPT_4 - GPT_4_0314 -> Known.GPT_4_0314 - GPT_4_0613 -> Known.GPT_4_0613 - GPT_4_32K -> Known.GPT_4_32K - GPT_4_32K_0314 -> Known.GPT_4_32K_0314 - GPT_4_32K_0613 -> Known.GPT_4_32K_0613 - GPT_3_5_TURBO -> Known.GPT_3_5_TURBO - GPT_3_5_TURBO_16K -> Known.GPT_3_5_TURBO_16K - GPT_3_5_TURBO_0301 -> Known.GPT_3_5_TURBO_0301 - GPT_3_5_TURBO_0613 -> Known.GPT_3_5_TURBO_0613 - GPT_3_5_TURBO_1106 -> Known.GPT_3_5_TURBO_1106 - GPT_3_5_TURBO_0125 -> Known.GPT_3_5_TURBO_0125 - GPT_3_5_TURBO_16K_0613 -> Known.GPT_3_5_TURBO_16K_0613 - else -> throw OmnistackInvalidDataException("Unknown UnionMember1: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } + fun asString(): String = _value().asStringOrThrow() } @JsonDeserialize(using = FunctionCall.Deserializer::class) @@ -5839,6 +5711,7 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): FunctionCall { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { return FunctionCall(unionMember0 = it, _json = json) } @@ -6001,7 +5874,7 @@ constructor( } fun build(): ChatCompletionFunctionCallOption = - ChatCompletionFunctionCallOption(name, additionalProperties.toUnmodifiable()) + ChatCompletionFunctionCallOption(name, additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -6126,7 +5999,7 @@ constructor( description, checkNotNull(name) { "`name` is required but was not set" }, parameters, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -6179,7 +6052,7 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Parameters = Parameters(additionalProperties.toUnmodifiable()) + fun build(): Parameters = Parameters(additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -6272,7 +6145,7 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): LogitBias = LogitBias(additionalProperties.toUnmodifiable()) + fun build(): LogitBias = LogitBias(additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -6411,6 +6284,7 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): ResponseFormat { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef()) { it.validate() } ?.let { return ResponseFormat(responseFormatText = it, _json = json) @@ -6516,7 +6390,7 @@ constructor( } fun build(): ResponseFormatText = - ResponseFormatText(type, additionalProperties.toUnmodifiable()) + ResponseFormatText(type, additionalProperties.toImmutable()) } class Type @@ -6659,7 +6533,7 @@ constructor( } fun build(): ResponseFormatJsonObject = - ResponseFormatJsonObject(type, additionalProperties.toUnmodifiable()) + ResponseFormatJsonObject(type, additionalProperties.toImmutable()) } class Type @@ -6821,7 +6695,7 @@ constructor( ResponseFormatJsonSchema( type, jsonSchema, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -7000,7 +6874,7 @@ constructor( name, schema, strict, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -7055,7 +6929,7 @@ constructor( additionalProperties: Map ) = apply { this.additionalProperties.putAll(additionalProperties) } - fun build(): Schema = Schema(additionalProperties.toUnmodifiable()) + fun build(): Schema = Schema(additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -7314,6 +7188,7 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Stop { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { return Stop(string = it, _json = json) } @@ -7404,7 +7279,7 @@ constructor( } fun build(): StreamOptions = - StreamOptions(includeUsage, additionalProperties.toUnmodifiable()) + StreamOptions(includeUsage, additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -7530,6 +7405,7 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): ToolChoice { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { return ToolChoice(unionMember0 = it, _json = json) } @@ -7714,7 +7590,7 @@ constructor( ChatCompletionNamedToolChoice( type, function, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -7785,7 +7661,7 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Function = Function(name, additionalProperties.toUnmodifiable()) + fun build(): Function = Function(name, additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -7943,7 +7819,7 @@ constructor( Tool( checkNotNull(type) { "`type` is required but was not set" }, checkNotNull(function) { "`function` is required but was not set" }, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -8069,7 +7945,7 @@ constructor( checkNotNull(name) { "`name` is required but was not set" }, parameters, strict, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -8122,7 +7998,7 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): Parameters = Parameters(additionalProperties.toUnmodifiable()) + fun build(): Parameters = Parameters(additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateResponse.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateResponse.kt index 869e9e4..d9acc67 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateResponse.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ChatCompletionCreateResponse.kt @@ -13,7 +13,7 @@ import com.omnistack.api.core.JsonField import com.omnistack.api.core.JsonMissing import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.toImmutable import com.omnistack.api.errors.OmnistackInvalidDataException import java.util.Objects @@ -248,14 +248,14 @@ private constructor( fun build(): ChatCompletionCreateResponse = ChatCompletionCreateResponse( id, - choices.map { it.toUnmodifiable() }, + choices.map { it.toImmutable() }, created, model, serviceTier, systemFingerprint, object_, usage, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -411,7 +411,7 @@ private constructor( index, message, logprobs, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -578,9 +578,9 @@ private constructor( fun build(): Logprobs = Logprobs( - content.map { it.toUnmodifiable() }, - refusal.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + content.map { it.toImmutable() }, + refusal.map { it.toImmutable() }, + additionalProperties.toImmutable(), ) } @@ -766,9 +766,9 @@ private constructor( Content( token, logprob, - bytes.map { it.toUnmodifiable() }, - topLogprobs.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + bytes.map { it.toImmutable() }, + topLogprobs.map { it.toImmutable() }, + additionalProperties.toImmutable(), ) } @@ -920,8 +920,8 @@ private constructor( TopLogprob( token, logprob, - bytes.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + bytes.map { it.toImmutable() }, + additionalProperties.toImmutable(), ) } @@ -1149,9 +1149,9 @@ private constructor( Refusal( token, logprob, - bytes.map { it.toUnmodifiable() }, - topLogprobs.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + bytes.map { it.toImmutable() }, + topLogprobs.map { it.toImmutable() }, + additionalProperties.toImmutable(), ) } @@ -1303,8 +1303,8 @@ private constructor( TopLogprob( token, logprob, - bytes.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + bytes.map { it.toImmutable() }, + additionalProperties.toImmutable(), ) } @@ -1532,10 +1532,10 @@ private constructor( Message( content, refusal, - toolCalls.map { it.toUnmodifiable() }, + toolCalls.map { it.toImmutable() }, role, functionCall, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -1705,7 +1705,7 @@ private constructor( FunctionCall( arguments, name, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -1838,7 +1838,7 @@ private constructor( id, type, function, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -1955,7 +1955,7 @@ private constructor( Function( name, arguments, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -2344,7 +2344,7 @@ private constructor( promptTokens, totalTokens, completionTokensDetails, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -2422,7 +2422,7 @@ private constructor( } fun build(): CompletionTokensDetails = - CompletionTokensDetails(reasoningTokens, additionalProperties.toUnmodifiable()) + CompletionTokensDetails(reasoningTokens, additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateParams.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateParams.kt index 5796060..68edf25 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateParams.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateParams.kt @@ -21,7 +21,9 @@ import com.omnistack.api.core.JsonField import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect import com.omnistack.api.core.getOrThrow -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.http.Headers +import com.omnistack.api.core.http.QueryParams +import com.omnistack.api.core.toImmutable import com.omnistack.api.errors.OmnistackInvalidDataException import com.omnistack.api.models.* import java.util.Objects @@ -46,8 +48,8 @@ constructor( private val temperature: Double?, private val topP: Double?, private val user: String?, - private val additionalQueryParams: Map>, - private val additionalHeaders: Map>, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) { @@ -111,9 +113,9 @@ constructor( ) } - internal fun getQueryParams(): Map> = additionalQueryParams + internal fun getHeaders(): Headers = additionalHeaders - internal fun getHeaders(): Map> = additionalHeaders + internal fun getQueryParams(): QueryParams = additionalQueryParams @JsonDeserialize(builder = CompletionCreateBody.Builder::class) @NoAutoDetect @@ -552,7 +554,7 @@ constructor( temperature, topP, user, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -577,9 +579,9 @@ constructor( "CompletionCreateBody{model=$model, prompt=$prompt, bestOf=$bestOf, echo=$echo, frequencyPenalty=$frequencyPenalty, logitBias=$logitBias, logprobs=$logprobs, maxTokens=$maxTokens, n=$n, presencePenalty=$presencePenalty, seed=$seed, stop=$stop, stream=$stream, streamOptions=$streamOptions, suffix=$suffix, temperature=$temperature, topP=$topP, user=$user, additionalProperties=$additionalProperties}" } - fun _additionalQueryParams(): Map> = additionalQueryParams + fun _additionalHeaders(): Headers = additionalHeaders - fun _additionalHeaders(): Map> = additionalHeaders + fun _additionalQueryParams(): QueryParams = additionalQueryParams fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -588,15 +590,15 @@ constructor( return true } - return /* spotless:off */ other is CompletionCreateParams && this.model == other.model && this.prompt == other.prompt && this.bestOf == other.bestOf && this.echo == other.echo && this.frequencyPenalty == other.frequencyPenalty && this.logitBias == other.logitBias && this.logprobs == other.logprobs && this.maxTokens == other.maxTokens && this.n == other.n && this.presencePenalty == other.presencePenalty && this.seed == other.seed && this.stop == other.stop && this.stream == other.stream && this.streamOptions == other.streamOptions && this.suffix == other.suffix && this.temperature == other.temperature && this.topP == other.topP && this.user == other.user && this.additionalQueryParams == other.additionalQueryParams && this.additionalHeaders == other.additionalHeaders && this.additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ + return /* spotless:off */ other is CompletionCreateParams && this.model == other.model && this.prompt == other.prompt && this.bestOf == other.bestOf && this.echo == other.echo && this.frequencyPenalty == other.frequencyPenalty && this.logitBias == other.logitBias && this.logprobs == other.logprobs && this.maxTokens == other.maxTokens && this.n == other.n && this.presencePenalty == other.presencePenalty && this.seed == other.seed && this.stop == other.stop && this.stream == other.stream && this.streamOptions == other.streamOptions && this.suffix == other.suffix && this.temperature == other.temperature && this.topP == other.topP && this.user == other.user && this.additionalHeaders == other.additionalHeaders && this.additionalQueryParams == other.additionalQueryParams && this.additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ } override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(model, prompt, bestOf, echo, frequencyPenalty, logitBias, logprobs, maxTokens, n, presencePenalty, seed, stop, stream, streamOptions, suffix, temperature, topP, user, additionalQueryParams, additionalHeaders, additionalBodyProperties) /* spotless:on */ + return /* spotless:off */ Objects.hash(model, prompt, bestOf, echo, frequencyPenalty, logitBias, logprobs, maxTokens, n, presencePenalty, seed, stop, stream, streamOptions, suffix, temperature, topP, user, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */ } override fun toString() = - "CompletionCreateParams{model=$model, prompt=$prompt, bestOf=$bestOf, echo=$echo, frequencyPenalty=$frequencyPenalty, logitBias=$logitBias, logprobs=$logprobs, maxTokens=$maxTokens, n=$n, presencePenalty=$presencePenalty, seed=$seed, stop=$stop, stream=$stream, streamOptions=$streamOptions, suffix=$suffix, temperature=$temperature, topP=$topP, user=$user, additionalQueryParams=$additionalQueryParams, additionalHeaders=$additionalHeaders, additionalBodyProperties=$additionalBodyProperties}" + "CompletionCreateParams{model=$model, prompt=$prompt, bestOf=$bestOf, echo=$echo, frequencyPenalty=$frequencyPenalty, logitBias=$logitBias, logprobs=$logprobs, maxTokens=$maxTokens, n=$n, presencePenalty=$presencePenalty, seed=$seed, stop=$stop, stream=$stream, streamOptions=$streamOptions, suffix=$suffix, temperature=$temperature, topP=$topP, user=$user, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" fun toBuilder() = Builder().from(this) @@ -626,8 +628,8 @@ constructor( private var temperature: Double? = null private var topP: Double? = null private var user: 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() private var additionalBodyProperties: MutableMap = mutableMapOf() internal fun from(completionCreateParams: CompletionCreateParams) = apply { @@ -649,8 +651,8 @@ constructor( this.temperature = completionCreateParams.temperature this.topP = completionCreateParams.topP this.user = completionCreateParams.user - additionalQueryParams(completionCreateParams.additionalQueryParams) additionalHeaders(completionCreateParams.additionalHeaders) + additionalQueryParams(completionCreateParams.additionalQueryParams) additionalBodyProperties(completionCreateParams.additionalBodyProperties) } @@ -666,16 +668,7 @@ constructor( * API to see all of your available models, or see our * [Model overview](/docs/models/overview) for descriptions of them. */ - fun model(string: String) = apply { this.model = Model.ofString(string) } - - /** - * ID of the model to use. You can use the [List models](/docs/api-reference/models/list) - * API to see all of your available models, or see our - * [Model overview](/docs/models/overview) for descriptions of them. - */ - fun model(unionMember1: Model.UnionMember1) = apply { - this.model = Model.ofUnionMember1(unionMember1) - } + fun model(value: String) = apply { this.model = Model.of(value) } /** * The prompt(s) to generate completions for, encoded as a string, array of strings, array @@ -705,7 +698,9 @@ constructor( * if a prompt is not specified the model will generate as if from the beginning of a new * document. */ - fun prompt(strings: List) = apply { this.prompt = Prompt.ofStrings(strings) } + fun promptOfStrings(strings: List) = apply { + this.prompt = Prompt.ofStrings(strings) + } /** * The prompt(s) to generate completions for, encoded as a string, array of strings, array @@ -715,7 +710,7 @@ constructor( * if a prompt is not specified the model will generate as if from the beginning of a new * document. */ - fun prompt(longs: List) = apply { this.prompt = Prompt.ofLongs(longs) } + fun promptOfLongs(longs: List) = apply { this.prompt = Prompt.ofLongs(longs) } /** * The prompt(s) to generate completions for, encoded as a string, array of strings, array @@ -725,7 +720,7 @@ constructor( * if a prompt is not specified the model will generate as if from the beginning of a new * document. */ - fun prompt(longs: List>) = apply { this.prompt = Prompt.ofLongs(longs) } + fun promptOfLists(lists: List>) = apply { this.prompt = Prompt.ofLists(lists) } /** * Generates `best_of` completions server-side and returns the "best" (the one with the @@ -836,7 +831,7 @@ constructor( * Up to 4 sequences where the API will stop generating further tokens. The returned text * will not contain the stop sequence. */ - fun stop(strings: List) = apply { this.stop = Stop.ofStrings(strings) } + fun stopOfStrings(strings: List) = apply { this.stop = Stop.ofStrings(strings) } /** * Whether to stream back partial progress. If set, tokens will be sent as data-only @@ -882,53 +877,111 @@ constructor( */ fun user(user: String) = apply { this.user = user } - 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 removeHeader(name: String) = apply { this.additionalHeaders.put(name, mutableListOf()) } + 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() - 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) = @@ -936,6 +989,14 @@ constructor( this.additionalBodyProperties.putAll(additionalBodyProperties) } + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + fun build(): CompletionCreateParams = CompletionCreateParams( checkNotNull(model) { "`model` is required but was not set" }, @@ -956,186 +1017,73 @@ constructor( temperature, topP, user, - additionalQueryParams.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalHeaders.mapValues { it.value.toUnmodifiable() }.toUnmodifiable(), - additionalBodyProperties.toUnmodifiable(), + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } - @JsonDeserialize(using = Model.Deserializer::class) - @JsonSerialize(using = Model.Serializer::class) class Model + @JsonCreator private constructor( - private val string: String? = null, - private val unionMember1: UnionMember1? = null, - private val _json: JsonValue? = null, - ) { - - private var validated: Boolean = false + private val value: JsonField, + ) : Enum { - fun string(): String? = string - - fun unionMember1(): UnionMember1? = unionMember1 - - fun isString(): Boolean = string != null - - fun isUnionMember1(): Boolean = unionMember1 != null - - fun asString(): String = string.getOrThrow("string") - - fun asUnionMember1(): UnionMember1 = unionMember1.getOrThrow("unionMember1") - - fun _json(): JsonValue? = _json - - fun accept(visitor: Visitor): T { - return when { - string != null -> visitor.visitString(string) - unionMember1 != null -> visitor.visitUnionMember1(unionMember1) - else -> visitor.unknown(_json) - } - } - - fun validate(): Model = apply { - if (!validated) { - if (string == null && unionMember1 == null) { - throw OmnistackInvalidDataException("Unknown Model: $_json") - } - validated = true - } - } + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Model && this.string == other.string && this.unionMember1 == other.unionMember1 /* spotless:on */ + return /* spotless:off */ other is Model && this.value == other.value /* spotless:on */ } - override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(string, unionMember1) /* spotless:on */ - } + override fun hashCode() = value.hashCode() - override fun toString(): String { - return when { - string != null -> "Model{string=$string}" - unionMember1 != null -> "Model{unionMember1=$unionMember1}" - _json != null -> "Model{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Model") - } - } + override fun toString() = value.toString() companion object { - fun ofString(string: String) = Model(string = string) + val GPT_3_5_TURBO_INSTRUCT = Model(JsonField.of("gpt-3.5-turbo-instruct")) - fun ofUnionMember1(unionMember1: UnionMember1) = Model(unionMember1 = unionMember1) - } - - interface Visitor { - - fun visitString(string: String): T + val DAVINCI_002 = Model(JsonField.of("davinci-002")) - fun visitUnionMember1(unionMember1: UnionMember1): T + val BABBAGE_002 = Model(JsonField.of("babbage-002")) - fun unknown(json: JsonValue?): T { - throw OmnistackInvalidDataException("Unknown Model: $json") - } + fun of(value: String) = Model(JsonField.of(value)) } - class Deserializer : BaseDeserializer(Model::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Model { - val json = JsonValue.fromJsonNode(node) - tryDeserialize(node, jacksonTypeRef())?.let { - return Model(string = it, _json = json) - } - tryDeserialize(node, jacksonTypeRef())?.let { - return Model(unionMember1 = it, _json = json) - } - - return Model(_json = json) - } + enum class Known { + GPT_3_5_TURBO_INSTRUCT, + DAVINCI_002, + BABBAGE_002, } - class Serializer : BaseSerializer(Model::class) { - - override fun serialize( - value: Model, - generator: JsonGenerator, - provider: SerializerProvider - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.unionMember1 != null -> generator.writeObject(value.unionMember1) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Model") - } - } + enum class Value { + GPT_3_5_TURBO_INSTRUCT, + DAVINCI_002, + BABBAGE_002, + _UNKNOWN, } - class UnionMember1 - @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 /* spotless:off */ other is UnionMember1 && this.value == other.value /* spotless:on */ + fun value(): Value = + when (this) { + GPT_3_5_TURBO_INSTRUCT -> Value.GPT_3_5_TURBO_INSTRUCT + DAVINCI_002 -> Value.DAVINCI_002 + BABBAGE_002 -> Value.BABBAGE_002 + else -> Value._UNKNOWN } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - - companion object { - - val GPT_3_5_TURBO_INSTRUCT = UnionMember1(JsonField.of("gpt-3.5-turbo-instruct")) - - val DAVINCI_002 = UnionMember1(JsonField.of("davinci-002")) - - val BABBAGE_002 = UnionMember1(JsonField.of("babbage-002")) - - fun of(value: String) = UnionMember1(JsonField.of(value)) + fun known(): Known = + when (this) { + GPT_3_5_TURBO_INSTRUCT -> Known.GPT_3_5_TURBO_INSTRUCT + DAVINCI_002 -> Known.DAVINCI_002 + BABBAGE_002 -> Known.BABBAGE_002 + else -> throw OmnistackInvalidDataException("Unknown Model: $value") } - enum class Known { - GPT_3_5_TURBO_INSTRUCT, - DAVINCI_002, - BABBAGE_002, - } - - enum class Value { - GPT_3_5_TURBO_INSTRUCT, - DAVINCI_002, - BABBAGE_002, - _UNKNOWN, - } - - fun value(): Value = - when (this) { - GPT_3_5_TURBO_INSTRUCT -> Value.GPT_3_5_TURBO_INSTRUCT - DAVINCI_002 -> Value.DAVINCI_002 - BABBAGE_002 -> Value.BABBAGE_002 - else -> Value._UNKNOWN - } - - fun known(): Known = - when (this) { - GPT_3_5_TURBO_INSTRUCT -> Known.GPT_3_5_TURBO_INSTRUCT - DAVINCI_002 -> Known.DAVINCI_002 - BABBAGE_002 -> Known.BABBAGE_002 - else -> throw OmnistackInvalidDataException("Unknown UnionMember1: $value") - } - - fun asString(): String = _value().asStringOrThrow() - } + fun asString(): String = _value().asStringOrThrow() } @JsonDeserialize(using = Prompt.Deserializer::class) @@ -1145,7 +1093,7 @@ constructor( private val string: String? = null, private val strings: List? = null, private val longs: List? = null, - private val longs: List>? = null, + private val lists: List>? = null, private val _json: JsonValue? = null, ) { @@ -1157,7 +1105,7 @@ constructor( fun longs(): List? = longs - fun longs(): List>? = longs + fun lists(): List>? = lists fun isString(): Boolean = string != null @@ -1165,7 +1113,7 @@ constructor( fun isLongs(): Boolean = longs != null - fun isLongs(): Boolean = longs != null + fun isLists(): Boolean = lists != null fun asString(): String = string.getOrThrow("string") @@ -1173,7 +1121,7 @@ constructor( fun asLongs(): List = longs.getOrThrow("longs") - fun asLongs(): List> = longs.getOrThrow("longs") + fun asLists(): List> = lists.getOrThrow("lists") fun _json(): JsonValue? = _json @@ -1182,14 +1130,14 @@ constructor( string != null -> visitor.visitString(string) strings != null -> visitor.visitStrings(strings) longs != null -> visitor.visitLongs(longs) - longs != null -> visitor.visitLongs(longs) + lists != null -> visitor.visitLists(lists) else -> visitor.unknown(_json) } } fun validate(): Prompt = apply { if (!validated) { - if (string == null && strings == null && longs == null && longs == null) { + if (string == null && strings == null && longs == null && lists == null) { throw OmnistackInvalidDataException("Unknown Prompt: $_json") } validated = true @@ -1201,11 +1149,11 @@ constructor( return true } - return /* spotless:off */ other is Prompt && this.string == other.string && this.strings == other.strings && this.longs == other.longs && this.longs == other.longs /* spotless:on */ + return /* spotless:off */ other is Prompt && this.string == other.string && this.strings == other.strings && this.longs == other.longs && this.lists == other.lists /* spotless:on */ } override fun hashCode(): Int { - return /* spotless:off */ Objects.hash(string, strings, longs, longs) /* spotless:on */ + return /* spotless:off */ Objects.hash(string, strings, longs, lists) /* spotless:on */ } override fun toString(): String { @@ -1213,7 +1161,7 @@ constructor( string != null -> "Prompt{string=$string}" strings != null -> "Prompt{strings=$strings}" longs != null -> "Prompt{longs=$longs}" - longs != null -> "Prompt{longs=$longs}" + lists != null -> "Prompt{lists=$lists}" _json != null -> "Prompt{_unknown=$_json}" else -> throw IllegalStateException("Invalid Prompt") } @@ -1227,7 +1175,7 @@ constructor( fun ofLongs(longs: List) = Prompt(longs = longs) - fun ofLongs(longs: List>) = Prompt(longs = longs) + fun ofLists(lists: List>) = Prompt(lists = lists) } interface Visitor { @@ -1238,7 +1186,7 @@ constructor( fun visitLongs(longs: List): T - fun visitLongs(longs: List>): T + fun visitLists(lists: List>): T fun unknown(json: JsonValue?): T { throw OmnistackInvalidDataException("Unknown Prompt: $json") @@ -1249,6 +1197,7 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Prompt { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { return Prompt(string = it, _json = json) } @@ -1259,7 +1208,7 @@ constructor( return Prompt(longs = it, _json = json) } tryDeserialize(node, jacksonTypeRef>>())?.let { - return Prompt(longs = it, _json = json) + return Prompt(lists = it, _json = json) } return Prompt(_json = json) @@ -1277,7 +1226,7 @@ constructor( value.string != null -> generator.writeObject(value.string) value.strings != null -> generator.writeObject(value.strings) value.longs != null -> generator.writeObject(value.longs) - value.longs != null -> generator.writeObject(value.longs) + value.lists != null -> generator.writeObject(value.lists) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Prompt") } @@ -1338,7 +1287,7 @@ constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): LogitBias = LogitBias(additionalProperties.toUnmodifiable()) + fun build(): LogitBias = LogitBias(additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -1446,6 +1395,7 @@ constructor( override fun ObjectCodec.deserialize(node: JsonNode): Stop { val json = JsonValue.fromJsonNode(node) + tryDeserialize(node, jacksonTypeRef())?.let { return Stop(string = it, _json = json) } @@ -1536,7 +1486,7 @@ constructor( } fun build(): StreamOptions = - StreamOptions(includeUsage, additionalProperties.toUnmodifiable()) + StreamOptions(includeUsage, additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateResponse.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateResponse.kt index eedc362..3bc8592 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateResponse.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/CompletionCreateResponse.kt @@ -13,7 +13,7 @@ import com.omnistack.api.core.JsonField import com.omnistack.api.core.JsonMissing import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.toImmutable import com.omnistack.api.errors.OmnistackInvalidDataException import java.util.Objects @@ -219,13 +219,13 @@ private constructor( fun build(): CompletionCreateResponse = CompletionCreateResponse( id, - choices.map { it.toUnmodifiable() }, + choices.map { it.toImmutable() }, created, model, systemFingerprint, object_, usage, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -365,7 +365,7 @@ private constructor( index, logprobs, text, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -547,11 +547,11 @@ private constructor( fun build(): Logprobs = Logprobs( - textOffset.map { it.toUnmodifiable() }, - tokenLogprobs.map { it.toUnmodifiable() }, - tokens.map { it.toUnmodifiable() }, - topLogprobs.map { it.toUnmodifiable() }, - additionalProperties.toUnmodifiable(), + textOffset.map { it.toImmutable() }, + tokenLogprobs.map { it.toImmutable() }, + tokens.map { it.toImmutable() }, + topLogprobs.map { it.toImmutable() }, + additionalProperties.toImmutable(), ) } @@ -604,7 +604,7 @@ private constructor( this.additionalProperties.putAll(additionalProperties) } - fun build(): TopLogprob = TopLogprob(additionalProperties.toUnmodifiable()) + fun build(): TopLogprob = TopLogprob(additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { @@ -861,7 +861,7 @@ private constructor( promptTokens, totalTokens, completionTokensDetails, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -939,7 +939,7 @@ private constructor( } fun build(): CompletionTokensDetails = - CompletionTokensDetails(reasoningTokens, additionalProperties.toUnmodifiable()) + CompletionTokensDetails(reasoningTokens, additionalProperties.toImmutable()) } override fun equals(other: Any?): Boolean { diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectApiKey.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectApiKey.kt index c98eb85..6bb5b5c 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectApiKey.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectApiKey.kt @@ -13,7 +13,7 @@ import com.omnistack.api.core.JsonField import com.omnistack.api.core.JsonMissing import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.toImmutable import com.omnistack.api.errors.OmnistackInvalidDataException import java.util.Objects @@ -178,7 +178,7 @@ private constructor( createdAt, id, owner, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } @@ -343,7 +343,7 @@ private constructor( type, user, serviceAccount, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectServiceAccount.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectServiceAccount.kt index 435adb4..bfa8eaa 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectServiceAccount.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectServiceAccount.kt @@ -13,7 +13,7 @@ import com.omnistack.api.core.JsonField import com.omnistack.api.core.JsonMissing import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.toImmutable import com.omnistack.api.errors.OmnistackInvalidDataException import java.util.Objects @@ -161,7 +161,7 @@ private constructor( name, role, createdAt, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectUser.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectUser.kt index 8f437eb..fee5e9d 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectUser.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/models/ProjectUser.kt @@ -13,7 +13,7 @@ import com.omnistack.api.core.JsonField import com.omnistack.api.core.JsonMissing import com.omnistack.api.core.JsonValue import com.omnistack.api.core.NoAutoDetect -import com.omnistack.api.core.toUnmodifiable +import com.omnistack.api.core.toImmutable import com.omnistack.api.errors.OmnistackInvalidDataException import java.util.Objects @@ -180,7 +180,7 @@ private constructor( email, role, addedAt, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/ChatServiceAsync.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/ChatServiceAsync.kt index bf43aa0..a838633 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/ChatServiceAsync.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/ChatServiceAsync.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.services.async import com.omnistack.api.services.async.chats.CompletionServiceAsync diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsync.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsync.kt index 3d9b691..0860331 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsync.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsync.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.services.async import com.omnistack.api.core.RequestOptions diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsyncImpl.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsyncImpl.kt index 8650f8f..6dba0cf 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsyncImpl.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/CompletionServiceAsyncImpl.kt @@ -36,9 +36,9 @@ constructor( .method(HttpMethod.POST) .addPathSegments("completions") .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) + .replaceAllQueryParams(params.getQueryParams()) .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) + .replaceAllHeaders(params.getHeaders()) .body(json(clientOptions.jsonMapper, params.getBody())) .build() return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsync.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsync.kt index 8c73ac5..549848a 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsync.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsync.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.services.async.chats import com.omnistack.api.core.RequestOptions diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsyncImpl.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsyncImpl.kt index 96af4af..8f05147 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsyncImpl.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/async/chats/CompletionServiceAsyncImpl.kt @@ -36,9 +36,9 @@ constructor( .method(HttpMethod.POST) .addPathSegments("chat", "completions") .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) + .replaceAllQueryParams(params.getQueryParams()) .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) + .replaceAllHeaders(params.getHeaders()) .body(json(clientOptions.jsonMapper, params.getBody())) .build() return clientOptions.httpClient.executeAsync(request, requestOptions).let { response -> diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/ChatService.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/ChatService.kt index 0e27c52..76833bd 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/ChatService.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/ChatService.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.services.blocking import com.omnistack.api.services.blocking.chats.CompletionService diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionService.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionService.kt index 66db2c0..58f07cb 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionService.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionService.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.services.blocking import com.omnistack.api.core.RequestOptions diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionServiceImpl.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionServiceImpl.kt index 87c3e41..e7fabc4 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionServiceImpl.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/CompletionServiceImpl.kt @@ -36,9 +36,9 @@ constructor( .method(HttpMethod.POST) .addPathSegments("completions") .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) + .replaceAllQueryParams(params.getQueryParams()) .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) + .replaceAllHeaders(params.getHeaders()) .body(json(clientOptions.jsonMapper, params.getBody())) .build() return clientOptions.httpClient.execute(request, requestOptions).let { response -> diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionService.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionService.kt index 43728d2..1dfe901 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionService.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionService.kt @@ -1,7 +1,5 @@ // File generated from our OpenAPI spec by Stainless. -@file:Suppress("OVERLOADS_INTERFACE") // See https://youtrack.jetbrains.com/issue/KT-36102 - package com.omnistack.api.services.blocking.chats import com.omnistack.api.core.RequestOptions diff --git a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceImpl.kt b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceImpl.kt index 12ecc86..1420240 100644 --- a/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceImpl.kt +++ b/omnistack-kotlin-core/src/main/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceImpl.kt @@ -36,9 +36,9 @@ constructor( .method(HttpMethod.POST) .addPathSegments("chat", "completions") .putAllQueryParams(clientOptions.queryParams) - .putAllQueryParams(params.getQueryParams()) + .replaceAllQueryParams(params.getQueryParams()) .putAllHeaders(clientOptions.headers) - .putAllHeaders(params.getHeaders()) + .replaceAllHeaders(params.getHeaders()) .body(json(clientOptions.jsonMapper, params.getBody())) .build() return clientOptions.httpClient.execute(request, requestOptions).let { response -> diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/PhantomReachableTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/PhantomReachableTest.kt new file mode 100644 index 0000000..8205cdf --- /dev/null +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/PhantomReachableTest.kt @@ -0,0 +1,27 @@ +package com.omnistack.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(3000) + + assertThat(closed).isTrue() + } +} diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/HeadersTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/HeadersTest.kt new file mode 100644 index 0000000..71b7df2 --- /dev/null +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/HeadersTest.kt @@ -0,0 +1,274 @@ +package com.omnistack.api.core.http + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.catchThrowable +import org.assertj.core.api.Assumptions.assumeThat +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) + } + + @ParameterizedTest + @EnumSource + fun namesAreImmutable(testCase: TestCase) { + val headers = testCase.headers + val headerNamesCopy = headers.names().toSet() + + val throwable = catchThrowable { + (headers.names() as MutableSet).add("another name") + } + + assertThat(throwable).isInstanceOf(UnsupportedOperationException::class.java) + assertThat(headers.names()).isEqualTo(headerNamesCopy) + } + + @ParameterizedTest + @EnumSource + fun valuesAreImmutable(testCase: TestCase) { + val headers = testCase.headers + assumeThat(headers.size).isNotEqualTo(0) + val name = headers.names().first() + val headerValuesCopy = headers.values(name).toList() + + val throwable = catchThrowable { + (headers.values(name) as MutableList).add("another value") + } + + assertThat(throwable).isInstanceOf(UnsupportedOperationException::class.java) + assertThat(headers.values(name)).isEqualTo(headerValuesCopy) + } +} diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/HttpRequestTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/HttpRequestTest.kt deleted file mode 100644 index 53d2ea0..0000000 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/HttpRequestTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.omnistack.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/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/QueryParamsTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/QueryParamsTest.kt new file mode 100644 index 0000000..7c0a8a6 --- /dev/null +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/QueryParamsTest.kt @@ -0,0 +1,212 @@ +package com.omnistack.api.core.http + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.catchThrowable +import org.assertj.core.api.Assumptions.assumeThat +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) + } + + @ParameterizedTest + @EnumSource + fun keysAreImmutable(testCase: TestCase) { + val queryParams = testCase.queryParams + val queryParamKeysCopy = queryParams.keys().toSet() + + val throwable = catchThrowable { + (queryParams.keys() as MutableSet).add("another key") + } + + assertThat(throwable).isInstanceOf(UnsupportedOperationException::class.java) + assertThat(queryParams.keys()).isEqualTo(queryParamKeysCopy) + } + + @ParameterizedTest + @EnumSource + fun valuesAreImmutable(testCase: TestCase) { + val queryParams = testCase.queryParams + assumeThat(queryParams.size).isNotEqualTo(0) + val key = queryParams.keys().first() + val queryParamValuesCopy = queryParams.values(key).toList() + + val throwable = catchThrowable { + (queryParams.values(key) as MutableList).add("another value") + } + + assertThat(throwable).isInstanceOf(UnsupportedOperationException::class.java) + assertThat(queryParams.values(key)).isEqualTo(queryParamValuesCopy) + } +} diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/SerializerTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/SerializerTest.kt index c1653f5..588c244 100644 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/SerializerTest.kt +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/core/http/SerializerTest.kt @@ -92,7 +92,7 @@ internal class SerializerTest { fun build(): ClassWithBooleanFieldPrefixedWithIs = ClassWithBooleanFieldPrefixedWithIs( isActive, - additionalProperties.toUnmodifiable(), + additionalProperties.toImmutable(), ) } } diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/ChatCompletionCreateParamsTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/ChatCompletionCreateParamsTest.kt index 229bacf..47a9882 100644 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/ChatCompletionCreateParamsTest.kt +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/ChatCompletionCreateParamsTest.kt @@ -20,7 +20,7 @@ class ChatCompletionCreateParamsTest { ChatCompletionCreateParams.Message .ChatCompletionRequestSystemMessage .Content - .ofString("string") + .ofTextContent("string") ) .role( ChatCompletionCreateParams.Message @@ -33,7 +33,7 @@ class ChatCompletionCreateParamsTest { ) ) ) - .model(ChatCompletionCreateParams.Model.ofString("string")) + .model(ChatCompletionCreateParams.Model.O1_PREVIEW) .frequencyPenalty(2.0) .functionCall( ChatCompletionCreateParams.FunctionCall.ofUnionMember0( @@ -117,7 +117,7 @@ class ChatCompletionCreateParamsTest { ChatCompletionCreateParams.Message .ChatCompletionRequestSystemMessage .Content - .ofString("string") + .ofTextContent("string") ) .role( ChatCompletionCreateParams.Message @@ -130,7 +130,7 @@ class ChatCompletionCreateParamsTest { ) ) ) - .model(ChatCompletionCreateParams.Model.ofString("string")) + .model(ChatCompletionCreateParams.Model.O1_PREVIEW) .frequencyPenalty(2.0) .functionCall( ChatCompletionCreateParams.FunctionCall.ofUnionMember0( @@ -213,7 +213,7 @@ class ChatCompletionCreateParamsTest { ChatCompletionCreateParams.Message .ChatCompletionRequestSystemMessage .Content - .ofString("string") + .ofTextContent("string") ) .role( ChatCompletionCreateParams.Message @@ -226,7 +226,7 @@ class ChatCompletionCreateParamsTest { ) ) ) - assertThat(body.model()).isEqualTo(ChatCompletionCreateParams.Model.ofString("string")) + assertThat(body.model()).isEqualTo(ChatCompletionCreateParams.Model.O1_PREVIEW) assertThat(body.frequencyPenalty()).isEqualTo(2.0) assertThat(body.functionCall()) .isEqualTo( @@ -316,7 +316,7 @@ class ChatCompletionCreateParamsTest { ChatCompletionCreateParams.Message .ChatCompletionRequestSystemMessage .Content - .ofString("string") + .ofTextContent("string") ) .role( ChatCompletionCreateParams.Message @@ -328,7 +328,7 @@ class ChatCompletionCreateParamsTest { ) ) ) - .model(ChatCompletionCreateParams.Model.ofString("string")) + .model(ChatCompletionCreateParams.Model.O1_PREVIEW) .build() val body = params.getBody() assertThat(body).isNotNull @@ -342,7 +342,7 @@ class ChatCompletionCreateParamsTest { ChatCompletionCreateParams.Message .ChatCompletionRequestSystemMessage .Content - .ofString("string") + .ofTextContent("string") ) .role( ChatCompletionCreateParams.Message @@ -354,6 +354,6 @@ class ChatCompletionCreateParamsTest { ) ) ) - assertThat(body.model()).isEqualTo(ChatCompletionCreateParams.Model.ofString("string")) + assertThat(body.model()).isEqualTo(ChatCompletionCreateParams.Model.O1_PREVIEW) } } diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/CompletionCreateParamsTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/CompletionCreateParamsTest.kt index 02488b2..c1ead4a 100644 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/CompletionCreateParamsTest.kt +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/models/CompletionCreateParamsTest.kt @@ -11,7 +11,7 @@ class CompletionCreateParamsTest { @Test fun createCompletionCreateParams() { CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -38,7 +38,7 @@ class CompletionCreateParamsTest { fun getBody() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -61,7 +61,7 @@ class CompletionCreateParamsTest { .build() val body = params.getBody() assertThat(body).isNotNull - assertThat(body.model()).isEqualTo(CompletionCreateParams.Model.ofString("string")) + assertThat(body.model()).isEqualTo(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) assertThat(body.prompt()) .isEqualTo(CompletionCreateParams.Prompt.ofString("This is a test.")) assertThat(body.bestOf()).isEqualTo(20L) @@ -87,10 +87,10 @@ class CompletionCreateParamsTest { fun getBodyWithoutOptionalFields() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .build() val body = params.getBody() assertThat(body).isNotNull - assertThat(body.model()).isEqualTo(CompletionCreateParams.Model.ofString("string")) + assertThat(body.model()).isEqualTo(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) } } diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ErrorHandlingTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ErrorHandlingTest.kt index fddc8eb..993bbb8 100644 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ErrorHandlingTest.kt +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ErrorHandlingTest.kt @@ -7,15 +7,15 @@ 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.put 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 com.omnistack.api.client.OmnistackClient import com.omnistack.api.client.okhttp.OmnistackOkHttpClient import com.omnistack.api.core.JsonString +import com.omnistack.api.core.http.Headers import com.omnistack.api.core.jsonMapper import com.omnistack.api.errors.BadRequestException import com.omnistack.api.errors.InternalServerException @@ -31,7 +31,6 @@ import com.omnistack.api.models.* 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.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -58,7 +57,7 @@ class ErrorHandlingTest { fun completionsCreate200() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -133,7 +132,7 @@ class ErrorHandlingTest { fun completionsCreate400() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -162,7 +161,7 @@ class ErrorHandlingTest { assertThatThrownBy({ client.completions().create(params) }) .satisfies({ e -> - assertBadRequest(e, ImmutableListMultimap.of("Foo", "Bar"), OMNISTACK_ERROR) + assertBadRequest(e, Headers.builder().put("Foo", "Bar").build(), OMNISTACK_ERROR) }) } @@ -170,7 +169,7 @@ class ErrorHandlingTest { fun completionsCreate401() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -199,7 +198,7 @@ class ErrorHandlingTest { assertThatThrownBy({ client.completions().create(params) }) .satisfies({ e -> - assertUnauthorized(e, ImmutableListMultimap.of("Foo", "Bar"), OMNISTACK_ERROR) + assertUnauthorized(e, Headers.builder().put("Foo", "Bar").build(), OMNISTACK_ERROR) }) } @@ -207,7 +206,7 @@ class ErrorHandlingTest { fun completionsCreate403() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -236,7 +235,11 @@ class ErrorHandlingTest { assertThatThrownBy({ client.completions().create(params) }) .satisfies({ e -> - assertPermissionDenied(e, ImmutableListMultimap.of("Foo", "Bar"), OMNISTACK_ERROR) + assertPermissionDenied( + e, + Headers.builder().put("Foo", "Bar").build(), + OMNISTACK_ERROR + ) }) } @@ -244,7 +247,7 @@ class ErrorHandlingTest { fun completionsCreate404() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -273,7 +276,7 @@ class ErrorHandlingTest { assertThatThrownBy({ client.completions().create(params) }) .satisfies({ e -> - assertNotFound(e, ImmutableListMultimap.of("Foo", "Bar"), OMNISTACK_ERROR) + assertNotFound(e, Headers.builder().put("Foo", "Bar").build(), OMNISTACK_ERROR) }) } @@ -281,7 +284,7 @@ class ErrorHandlingTest { fun completionsCreate422() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -312,7 +315,7 @@ class ErrorHandlingTest { .satisfies({ e -> assertUnprocessableEntity( e, - ImmutableListMultimap.of("Foo", "Bar"), + Headers.builder().put("Foo", "Bar").build(), OMNISTACK_ERROR ) }) @@ -322,7 +325,7 @@ class ErrorHandlingTest { fun completionsCreate429() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -351,7 +354,7 @@ class ErrorHandlingTest { assertThatThrownBy({ client.completions().create(params) }) .satisfies({ e -> - assertRateLimit(e, ImmutableListMultimap.of("Foo", "Bar"), OMNISTACK_ERROR) + assertRateLimit(e, Headers.builder().put("Foo", "Bar").build(), OMNISTACK_ERROR) }) } @@ -359,7 +362,7 @@ class ErrorHandlingTest { fun completionsCreate500() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -388,7 +391,11 @@ class ErrorHandlingTest { assertThatThrownBy({ client.completions().create(params) }) .satisfies({ e -> - assertInternalServer(e, ImmutableListMultimap.of("Foo", "Bar"), OMNISTACK_ERROR) + assertInternalServer( + e, + Headers.builder().put("Foo", "Bar").build(), + OMNISTACK_ERROR + ) }) } @@ -396,7 +403,7 @@ class ErrorHandlingTest { fun unexpectedStatusCode() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -428,7 +435,7 @@ class ErrorHandlingTest { assertUnexpectedStatusCodeException( e, 999, - ImmutableListMultimap.of("Foo", "Bar"), + Headers.builder().put("Foo", "Bar").build(), toJson(OMNISTACK_ERROR) ) }) @@ -438,7 +445,7 @@ class ErrorHandlingTest { fun invalidBody() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -474,7 +481,7 @@ class ErrorHandlingTest { fun invalidErrorBody() { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) @@ -500,7 +507,7 @@ class ErrorHandlingTest { assertThatThrownBy({ client.completions().create(params) }) .satisfies({ e -> - assertBadRequest(e, ImmutableListMultimap.of(), OmnistackError.builder().build()) + assertBadRequest(e, Headers.builder().build(), OmnistackError.builder().build()) }) } @@ -511,7 +518,7 @@ class ErrorHandlingTest { private fun assertUnexpectedStatusCodeException( throwable: Throwable, statusCode: Int, - headers: ListMultimap, + headers: Headers, responseBody: ByteArray ) { assertThat(throwable) @@ -521,41 +528,33 @@ class ErrorHandlingTest { .satisfies({ e -> assertThat(e.statusCode()).isEqualTo(statusCode) assertThat(e.body()).isEqualTo(String(responseBody)) - assertThat(e.headers()).containsAllEntriesOf(headers) + assertThat(e.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } - private fun assertBadRequest( - throwable: Throwable, - headers: ListMultimap, - error: OmnistackError - ) { + private fun assertBadRequest(throwable: Throwable, headers: Headers, error: OmnistackError) { 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.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } - private fun assertUnauthorized( - throwable: Throwable, - headers: ListMultimap, - error: OmnistackError - ) { + private fun assertUnauthorized(throwable: Throwable, headers: Headers, error: OmnistackError) { 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) + assertThat(e.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } private fun assertPermissionDenied( throwable: Throwable, - headers: ListMultimap, + headers: Headers, error: OmnistackError ) { assertThat(throwable) @@ -565,27 +564,23 @@ class ErrorHandlingTest { .satisfies({ e -> assertThat(e.statusCode()).isEqualTo(403) assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) + assertThat(e.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } - private fun assertNotFound( - throwable: Throwable, - headers: ListMultimap, - error: OmnistackError - ) { + private fun assertNotFound(throwable: Throwable, headers: Headers, error: OmnistackError) { 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.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } private fun assertUnprocessableEntity( throwable: Throwable, - headers: ListMultimap, + headers: Headers, error: OmnistackError ) { assertThat(throwable) @@ -595,27 +590,23 @@ class ErrorHandlingTest { .satisfies({ e -> assertThat(e.statusCode()).isEqualTo(422) assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) + assertThat(e.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } - private fun assertRateLimit( - throwable: Throwable, - headers: ListMultimap, - error: OmnistackError - ) { + private fun assertRateLimit(throwable: Throwable, headers: Headers, error: OmnistackError) { 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) + assertThat(e.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } private fun assertInternalServer( throwable: Throwable, - headers: ListMultimap, + headers: Headers, error: OmnistackError ) { assertThat(throwable) @@ -623,7 +614,12 @@ class ErrorHandlingTest { .satisfies({ e -> assertThat(e.statusCode()).isEqualTo(500) assertThat(e.error()).isEqualTo(error) - assertThat(e.headers()).containsAllEntriesOf(headers) + assertThat(e.headers().toMap()).containsAllEntriesOf(headers.toMap()) }) } + + private fun Headers.toMap(): Map> = + mutableMapOf>().also { map -> + names().forEach { map[it] = values(it) } + } } diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ServiceParamsTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ServiceParamsTest.kt index 70d5e58..ae74900 100644 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ServiceParamsTest.kt +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/ServiceParamsTest.kt @@ -56,7 +56,7 @@ class ServiceParamsTest { val params = CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/ChatServiceTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/ChatServiceTest.kt deleted file mode 100644 index 7fffa08..0000000 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/ChatServiceTest.kt +++ /dev/null @@ -1,9 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.omnistack.api.services.blocking - -import com.omnistack.api.TestServerExtension -import com.omnistack.api.models.* -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(TestServerExtension::class) class ChatServiceTest diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/CompletionServiceTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/CompletionServiceTest.kt index 72788d3..c19316a 100644 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/CompletionServiceTest.kt +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/CompletionServiceTest.kt @@ -22,7 +22,7 @@ class CompletionServiceTest { val completionCreateResponse = completionService.create( CompletionCreateParams.builder() - .model(CompletionCreateParams.Model.ofString("string")) + .model(CompletionCreateParams.Model.GPT_3_5_TURBO_INSTRUCT) .prompt(CompletionCreateParams.Prompt.ofString("This is a test.")) .bestOf(20L) .echo(true) diff --git a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceTest.kt b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceTest.kt index 02a6233..e0644fb 100644 --- a/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceTest.kt +++ b/omnistack-kotlin-core/src/test/kotlin/com/omnistack/api/services/blocking/chats/CompletionServiceTest.kt @@ -32,7 +32,7 @@ class CompletionServiceTest { ChatCompletionCreateParams.Message .ChatCompletionRequestSystemMessage .Content - .ofString("string") + .ofTextContent("string") ) .role( ChatCompletionCreateParams.Message @@ -45,7 +45,7 @@ class CompletionServiceTest { ) ) ) - .model(ChatCompletionCreateParams.Model.ofString("string")) + .model(ChatCompletionCreateParams.Model.O1_PREVIEW) .frequencyPenalty(2.0) .functionCall( ChatCompletionCreateParams.FunctionCall.ofUnionMember0( diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..8f98719 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,67 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "simple", + "extra-files": [ + "README.md", + "build.gradle.kts" + ] +} \ No newline at end of file